diff options
author | steven <steven@138bc75d-0d04-0410-961f-82ee72b054a4> | 2012-06-29 16:12:35 +0000 |
---|---|---|
committer | steven <steven@138bc75d-0d04-0410-961f-82ee72b054a4> | 2012-06-29 16:12:35 +0000 |
commit | e53d55e7b556f38b546938e3a16cf2f8ed1e27d8 (patch) | |
tree | f78869254e81452ccc6da3411b5dc9dd8cc02315 /gcc/c | |
parent | 22d29d94535f12c8f3f6a0f2441137f1256a988d (diff) | |
download | gcc-e53d55e7b556f38b546938e3a16cf2f8ed1e27d8.tar.gz |
toplevel/
* configure.ac: Skip C if explicitly selected.
* configure: Regenerate.
gcc/
* configure.ac: Remove special gtfiles case for C.
* configure: Regenerate.
* Makefile.in: Remove C front-end hooks and build hooks that
will be picked up from c/Make-lang.in now.
Add tree-mudflap to C_COMMON_OBJS.
* gengtype.c (files_rules): Adjust gt-files for c/c-decl.c.
* config/vms/vms.c: Look for c-tree.h in c/.
* doc/gty.texi: Remove reference to c-config-lang.in.
* doc/sourcebuild.texi: Document the c/ subdirectory.
c/
* Make-lang.in: New file, rules migrated from gcc/Makefile.in
and add language Makefile hooks.
* config-lang.in: New file.
* c-config-lang.in: Moved from gcc/config-lang.in to here, and
add the required "normal" config-lang.in rules.
* c-lang.h: Moved from gcc/ to here.
* c-tree.h: Likewise.
* c-objc-common.c: Likewise.
* c-objc-common.h: Likewise.
* c-typeck.c: Likewise.
* c-convert.c: Likewise.
* c-lang.c: Likewise.
* c-aux-info.c: Likewise.
* c-errors.c: Likewise.
* gccspec.c: Likewise.
* c-decl.c: Likewise. Include gt-c-c-decl.h, not gt-c-decl.h.
* c-parser.c: Likewise. Include gt-c-c-parser.h, not gt-c-parser.h.
c-family/
* cppspec.c: Moved from gcc/ to here.
objc/
* Make-ang.in: Adjust for move of C front-end files.
* config-lang.in: Likewise.
* objc-encoding.c: Look for cp-tree.h in cp/, and for c-tree.h
and c-lang.h in c/.
* objc-runtime-shared-support.c: Likewise.
* objc-next-runtime-abi-01.c: Likewise.
* objc-next-runtime-abi-02.c: Likewise.
* objc-gnu-runtime-abi-01.c: Likewise.
* objc-act.c: Likewise.
* objc-lang.c: Likewise.
cp/
* Make-lang.in: Remove tree-mudflap.o from CXX_AND_OBJCXX_OBJS.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@189080 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/c')
-rw-r--r-- | gcc/c/ChangeLog | 25 | ||||
-rw-r--r-- | gcc/c/Make-lang.in | 196 | ||||
-rw-r--r-- | gcc/c/c-aux-info.c | 567 | ||||
-rw-r--r-- | gcc/c/c-convert.c | 183 | ||||
-rw-r--r-- | gcc/c/c-decl.c | 10155 | ||||
-rw-r--r-- | gcc/c/c-errors.c | 64 | ||||
-rw-r--r-- | gcc/c/c-lang.c | 52 | ||||
-rw-r--r-- | gcc/c/c-lang.h | 60 | ||||
-rw-r--r-- | gcc/c/c-objc-common.c | 214 | ||||
-rw-r--r-- | gcc/c/c-objc-common.h | 109 | ||||
-rw-r--r-- | gcc/c/c-parser.c | 10840 | ||||
-rw-r--r-- | gcc/c/c-tree.h | 676 | ||||
-rw-r--r-- | gcc/c/c-typeck.c | 10939 | ||||
-rw-r--r-- | gcc/c/config-lang.in | 34 | ||||
-rw-r--r-- | gcc/c/gccspec.c | 108 |
15 files changed, 34222 insertions, 0 deletions
diff --git a/gcc/c/ChangeLog b/gcc/c/ChangeLog new file mode 100644 index 00000000000..f8572aaa13f --- /dev/null +++ b/gcc/c/ChangeLog @@ -0,0 +1,25 @@ +2012-06-29 Steven Bosscher <steven@gcc.gnu.org> + + * Make-lang.in: New file, rules migrated from gcc/Makefile.in + and add language Makefile hooks. + * config-lang.in: New file. + * c-config-lang.in: Moved from gcc/config-lang.in to here, and + add the required "normal" config-lang.in rules. + * c-lang.h: Moved from gcc/ to here. + * c-tree.h: Likewise. + * c-objc-common.c: Likewise. + * c-objc-common.h: Likewise. + * c-typeck.c: Likewise. + * c-convert.c: Likewise. + * c-lang.c: Likewise. + * c-aux-info.c: Likewise. + * c-errors.c: Likewise. + * gccspec.c: Likewise. + * c-decl.c: Likewise. Include gt-c-c-decl.h, not gt-c-decl.h. + * c-parser.c: Likewise. Include gt-c-c-parser.h, not gt-c-parser.h. + +Copyright (C) 2012 Free Software Foundation, Inc. + +Copying and distribution of this file, with or without modification, +are permitted in any medium without royalty provided the copyright +notice and this notice are preserved. diff --git a/gcc/c/Make-lang.in b/gcc/c/Make-lang.in new file mode 100644 index 00000000000..08b1ba1a919 --- /dev/null +++ b/gcc/c/Make-lang.in @@ -0,0 +1,196 @@ +# Top level -*- makefile -*- fragment for GNU C - C language. +# Copyright (C) 1994, 1995, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, +# 2005, 2007, 2008, 2009, 2010, 2011, 2012 +# Free Software Foundation, Inc. + +#This file is part of GCC. + +#GCC 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 3, or (at your option) +#any later version. + +#GCC 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 GCC; see the file COPYING3. If not see +# <http://www.gnu.org/licenses/>. + +# This file provides the language dependent support in the main Makefile. +# Each language makefile fragment must provide the following targets: +# +# foo.all.cross, foo.start.encap, foo.rest.encap, +# foo.install-common, foo.install-man, foo.install-info, foo.install-pdf, +# foo.install-html, foo.info, foo.dvi, foo.pdf, foo.html, foo.uninstall, +# foo.mostlyclean, foo.clean, foo.distclean, +# foo.maintainer-clean, foo.stage1, foo.stage2, foo.stage3, foo.stage4 +# +# where `foo' is the name of the language. +# +# It should also provide rules for: +# +# - making any compiler driver (eg: gcc) +# - the compiler proper (eg: cc1) +# - define the names for selecting the language in LANGUAGES. + +# +# Define the names for selecting c in LANGUAGES. +c: cc1$(exeext) + +# Tell GNU make to ignore these if they exist. +.PHONY: c gcc + +# The C front end driver. This is different from the drivers for other +# front ends, because there is no C language specific driver (i.e. nothing +# is to cc1 as e.g. g++ is to cc1plus, or gfortran is to f951). +c/gccspec.o: c/gccspec.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(GCC_H) \ + $(OPTS_H) + (SHLIB='$(SHLIB)'; \ + $(COMPILER) $(ALL_COMPILERFLAGS) $(ALL_CPPFLAGS) \ + $(DRIVER_DEFINES) \ + -c $(srcdir)/c/gccspec.c $(OUTPUT_OPTION)) + +# The C compiler itself. + +# Language-specific object files for C and Objective C. +C_AND_OBJC_OBJS = attribs.o c/c-errors.o c/c-decl.o c/c-typeck.o \ + c/c-convert.o c/c-aux-info.o c/c-objc-common.o c/c-parser.o \ + $(C_COMMON_OBJS) $(C_TARGET_OBJS) + +# Language-specific object files for C. +C_OBJS = c/c-lang.o c-family/stub-objc.o $(C_AND_OBJC_OBJS) +c_OBJS = $(C_OBJS) cc1-checksum.o c/gccspec.o + +# Use strict warnings for this front end. +c-warn = $(STRICT_WARN) + +# compute checksum over all object files and the options +cc1-checksum.c : build/genchecksum$(build_exeext) checksum-options \ + $(C_OBJS) $(BACKEND) $(LIBDEPS) + build/genchecksum$(build_exeext) $(C_OBJS) $(BACKEND) $(LIBDEPS) \ + checksum-options > cc1-checksum.c.tmp && \ + $(srcdir)/../move-if-change cc1-checksum.c.tmp cc1-checksum.c + +cc1-checksum.o : cc1-checksum.c $(CONFIG_H) $(SYSTEM_H) + +cc1$(exeext): $(C_OBJS) cc1-checksum.o $(BACKEND) $(LIBDEPS) + +$(LINKER) $(ALL_LINKERFLAGS) $(LDFLAGS) -o $@ $(C_OBJS) \ + cc1-checksum.o $(BACKEND) $(LIBS) $(BACKENDLIBS) +# +# Build hooks: + +c.info: +c.dvi: +c.pdf: +c.html: +c.install-info: +c.install-pdf: +c.install-html: +c.all.cross: +c.start.encap: +c.rest.encap: +c.srcinfo: +c.srcextra: gengtype-lex.c + -cp -p $^ $(srcdir) +c.tags: force + cd $(srcdir)/c; etags -o TAGS.sub *.c *.h; \ + etags --include TAGS.sub --include ../TAGS.sub +c.man: +c.srcman: + +# List of targets that can use the generic check- rule and its // variant. +lang_checks += check-gcc +lang_checks_parallelized += check-gcc + +# 'make check' in gcc/ looks for check-c. Redirect it to check-gcc. +check-c : check-gcc + +# +# Install hooks: +# cc1 is installed elsewhere as part of $(COMPILERS). + +c.install-common: +c.install-man: +c.install-plugin: +c.uninstall: + +# +# Clean hooks: +# A lot of the ancillary files are deleted by the main makefile. +# We just have to delete files specific to us. + +c.mostlyclean: + -rm -f cc1$(exeext) + -rm -f c/*$(objext) + -rm -f c/*$(coverageexts) +c.clean: +c.distclean: + -rm -f c/config.status c/Makefile +c.maintainer-clean: +# +# Stage hooks: +# The main makefile has already created stage?/cp. + +c.stage1: stage1-start + -mv c/*$(objext) stage1/c +c.stage2: stage2-start + -mv c/*$(objext) stage2/c +c.stage3: stage3-start + -mv c/*$(objext) stage3/c +c.stage4: stage4-start + -mv c/*$(objext) stage4/c +c.stageprofile: stageprofile-start + -mv c/*$(objext) stageprofile/c +c.stagefeedback: stagefeedback-start + -mv c/*$(objext) stagefeedback/c + +# +# .o: .h dependencies. +# C language specific files. +C_TREE_H = c/c-tree.h $(C_COMMON_H) $(DIAGNOSTIC_H) +c/c-aux-info.o : c/c-aux-info.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \ + $(C_TREE_H) $(TREE_H) $(FLAGS_H) + +c/c-convert.o : c/c-convert.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \ + $(TREE_H) $(C_TREE_H) $(FLAGS_H) $(C_COMMON_H) convert.h \ + langhooks.h $(TARGET_H) + +c/c-decl.o : c/c-decl.c c/c-lang.h $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \ + $(TREE_H) $(C_TREE_H) $(GGC_H) $(TARGET_H) $(FLAGS_H) $(FUNCTION_H) \ + output.h debug.h toplev.h intl.h $(TM_P_H) $(TREE_INLINE_H) \ + $(TIMEVAR_H) $(OPTS_H) $(C_PRAGMA_H) gt-c-c-decl.h $(CGRAPH_H) \ + $(HASHTAB_H) $(LANGHOOKS_DEF_H) \ + $(TREE_DUMP_H) $(C_COMMON_H) $(CPPLIB_H) $(DIAGNOSTIC_CORE_H) \ + $(INPUT_H) langhooks.h pointer-set.h tree-iterator.h \ + $(PLUGIN_H) c-family/c-ada-spec.h c-family/c-objc.h + +c/c-errors.o: c/c-errors.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) \ + $(C_TREE_H) $(FLAGS_H) $(DIAGNOSTIC_H) $(TM_P_H) + +c/c-lang.o : c/c-lang.c c/c-objc-common.h \ + $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) \ + $(C_TREE_H) $(DIAGNOSTIC_CORE_H) \ + langhooks.h $(LANGHOOKS_DEF_H) $(C_COMMON_H) gtype-c.h \ + $(C_PRAGMA_H) $(TREE_INLINE_H) + +c/c-objc-common.o : c/c-objc-common.c c/c-objc-common.h \ + $(CONFIG_H) $(SYSTEM_H) coretypes.h \ + $(TREE_H) $(C_TREE_H) $(FLAGS_H) $(DIAGNOSTIC_H) \ + langhooks.h $(GGC_H) $(C_PRETTY_PRINT_H) intl.h \ + $(TREE_PRETTY_PRINT_H) + +c/c-parser.o : c/c-parser.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \ + $(TM_H) $(TREE_H) $(C_TREE_H) $(C_COMMON_H) $(C_PRAGMA_H) $(CPPLIB_H) \ + $(GGC_H) $(TIMEVAR_H) $(INPUT_H) $(FLAGS_H) \ + gt-c-c-parser.h langhooks.h \ + $(VEC_H) $(TARGET_H) $(CGRAPH_H) $(PLUGIN_H) \ + c-family/c-objc.h + +c/c-typeck.o : c/c-typeck.c c/c-lang.h $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \ + $(TREE_H) $(C_TREE_H) $(TARGET_H) $(FLAGS_H) intl.h \ + langhooks.h tree-iterator.h $(BITMAP_H) $(GIMPLE_H) \ + c-family/c-objc.h + diff --git a/gcc/c/c-aux-info.c b/gcc/c/c-aux-info.c new file mode 100644 index 00000000000..694f9c1f59e --- /dev/null +++ b/gcc/c/c-aux-info.c @@ -0,0 +1,567 @@ +/* Generate information regarding function declarations and definitions based + on information stored in GCC's tree structure. This code implements the + -aux-info option. + Copyright (C) 1989, 1991, 1994, 1995, 1997, 1998, + 1999, 2000, 2003, 2004, 2007, 2010 Free Software Foundation, Inc. + Contributed by Ron Guilmette (rfg@segfault.us.com). + +This file is part of GCC. + +GCC 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 3, or (at your option) any later +version. + +GCC 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 GCC; see the file COPYING3. If not see +<http://www.gnu.org/licenses/>. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "tm.h" +#include "flags.h" +#include "tree.h" +#include "c-tree.h" + +enum formals_style_enum { + ansi, + k_and_r_names, + k_and_r_decls +}; +typedef enum formals_style_enum formals_style; + + +static const char *data_type; + +static char *affix_data_type (const char *) ATTRIBUTE_MALLOC; +static const char *gen_formal_list_for_type (tree, formals_style); +static const char *gen_formal_list_for_func_def (tree, formals_style); +static const char *gen_type (const char *, tree, formals_style); +static const char *gen_decl (tree, int, formals_style); + +/* Given a string representing an entire type or an entire declaration + which only lacks the actual "data-type" specifier (at its left end), + affix the data-type specifier to the left end of the given type + specification or object declaration. + + Because of C language weirdness, the data-type specifier (which normally + goes in at the very left end) may have to be slipped in just to the + right of any leading "const" or "volatile" qualifiers (there may be more + than one). Actually this may not be strictly necessary because it seems + that GCC (at least) accepts `<data-type> const foo;' and treats it the + same as `const <data-type> foo;' but people are accustomed to seeing + `const char *foo;' and *not* `char const *foo;' so we try to create types + that look as expected. */ + +static char * +affix_data_type (const char *param) +{ + char *const type_or_decl = ASTRDUP (param); + char *p = type_or_decl; + char *qualifiers_then_data_type; + char saved; + + /* Skip as many leading const's or volatile's as there are. */ + + for (;;) + { + if (!strncmp (p, "volatile ", 9)) + { + p += 9; + continue; + } + if (!strncmp (p, "const ", 6)) + { + p += 6; + continue; + } + break; + } + + /* p now points to the place where we can insert the data type. We have to + add a blank after the data-type of course. */ + + if (p == type_or_decl) + return concat (data_type, " ", type_or_decl, NULL); + + saved = *p; + *p = '\0'; + qualifiers_then_data_type = concat (type_or_decl, data_type, NULL); + *p = saved; + return reconcat (qualifiers_then_data_type, + qualifiers_then_data_type, " ", p, NULL); +} + +/* Given a tree node which represents some "function type", generate the + source code version of a formal parameter list (of some given style) for + this function type. Return the whole formal parameter list (including + a pair of surrounding parens) as a string. Note that if the style + we are currently aiming for is non-ansi, then we just return a pair + of empty parens here. */ + +static const char * +gen_formal_list_for_type (tree fntype, formals_style style) +{ + const char *formal_list = ""; + tree formal_type; + + if (style != ansi) + return "()"; + + formal_type = TYPE_ARG_TYPES (fntype); + while (formal_type && TREE_VALUE (formal_type) != void_type_node) + { + const char *this_type; + + if (*formal_list) + formal_list = concat (formal_list, ", ", NULL); + + this_type = gen_type ("", TREE_VALUE (formal_type), ansi); + formal_list + = ((strlen (this_type)) + ? concat (formal_list, affix_data_type (this_type), NULL) + : concat (formal_list, data_type, NULL)); + + formal_type = TREE_CHAIN (formal_type); + } + + /* If we got to here, then we are trying to generate an ANSI style formal + parameters list. + + New style prototyped ANSI formal parameter lists should in theory always + contain some stuff between the opening and closing parens, even if it is + only "void". + + The brutal truth though is that there is lots of old K&R code out there + which contains declarations of "pointer-to-function" parameters and + these almost never have fully specified formal parameter lists associated + with them. That is, the pointer-to-function parameters are declared + with just empty parameter lists. + + In cases such as these, protoize should really insert *something* into + the vacant parameter lists, but what? It has no basis on which to insert + anything in particular. + + Here, we make life easy for protoize by trying to distinguish between + K&R empty parameter lists and new-style prototyped parameter lists + that actually contain "void". In the latter case we (obviously) want + to output the "void" verbatim, and that what we do. In the former case, + we do our best to give protoize something nice to insert. + + This "something nice" should be something that is still valid (when + re-compiled) but something that can clearly indicate to the user that + more typing information (for the parameter list) should be added (by + hand) at some convenient moment. + + The string chosen here is a comment with question marks in it. */ + + if (!*formal_list) + { + if (prototype_p (fntype)) + /* assert (TREE_VALUE (TYPE_ARG_TYPES (fntype)) == void_type_node); */ + formal_list = "void"; + else + formal_list = "/* ??? */"; + } + else + { + /* If there were at least some parameters, and if the formals-types-list + petered out to a NULL (i.e. without being terminated by a + void_type_node) then we need to tack on an ellipsis. */ + if (!formal_type) + formal_list = concat (formal_list, ", ...", NULL); + } + + return concat (" (", formal_list, ")", NULL); +} + +/* Generate a parameter list for a function definition (in some given style). + + Note that this routine has to be separate (and different) from the code that + generates the prototype parameter lists for function declarations, because + in the case of a function declaration, all we have to go on is a tree node + representing the function's own "function type". This can tell us the types + of all of the formal parameters for the function, but it cannot tell us the + actual *names* of each of the formal parameters. We need to output those + parameter names for each function definition. + + This routine gets a pointer to a tree node which represents the actual + declaration of the given function, and this DECL node has a list of formal + parameter (variable) declarations attached to it. These formal parameter + (variable) declaration nodes give us the actual names of the formal + parameters for the given function definition. + + This routine returns a string which is the source form for the entire + function formal parameter list. */ + +static const char * +gen_formal_list_for_func_def (tree fndecl, formals_style style) +{ + const char *formal_list = ""; + tree formal_decl; + + formal_decl = DECL_ARGUMENTS (fndecl); + while (formal_decl) + { + const char *this_formal; + + if (*formal_list && ((style == ansi) || (style == k_and_r_names))) + formal_list = concat (formal_list, ", ", NULL); + this_formal = gen_decl (formal_decl, 0, style); + if (style == k_and_r_decls) + formal_list = concat (formal_list, this_formal, "; ", NULL); + else + formal_list = concat (formal_list, this_formal, NULL); + formal_decl = TREE_CHAIN (formal_decl); + } + if (style == ansi) + { + if (!DECL_ARGUMENTS (fndecl)) + formal_list = concat (formal_list, "void", NULL); + if (stdarg_p (TREE_TYPE (fndecl))) + formal_list = concat (formal_list, ", ...", NULL); + } + if ((style == ansi) || (style == k_and_r_names)) + formal_list = concat (" (", formal_list, ")", NULL); + return formal_list; +} + +/* Generate a string which is the source code form for a given type (t). This + routine is ugly and complex because the C syntax for declarations is ugly + and complex. This routine is straightforward so long as *no* pointer types, + array types, or function types are involved. + + In the simple cases, this routine will return the (string) value which was + passed in as the "ret_val" argument. Usually, this starts out either as an + empty string, or as the name of the declared item (i.e. the formal function + parameter variable). + + This routine will also return with the global variable "data_type" set to + some string value which is the "basic" data-type of the given complete type. + This "data_type" string can be concatenated onto the front of the returned + string after this routine returns to its caller. + + In complicated cases involving pointer types, array types, or function + types, the C declaration syntax requires an "inside out" approach, i.e. if + you have a type which is a "pointer-to-function" type, you need to handle + the "pointer" part first, but it also has to be "innermost" (relative to + the declaration stuff for the "function" type). Thus, is this case, you + must prepend a "(*" and append a ")" to the name of the item (i.e. formal + variable). Then you must append and prepend the other info for the + "function type" part of the overall type. + + To handle the "innermost precedence" rules of complicated C declarators, we + do the following (in this routine). The input parameter called "ret_val" + is treated as a "seed". Each time gen_type is called (perhaps recursively) + some additional strings may be appended or prepended (or both) to the "seed" + string. If yet another (lower) level of the GCC tree exists for the given + type (as in the case of a pointer type, an array type, or a function type) + then the (wrapped) seed is passed to a (recursive) invocation of gen_type() + this recursive invocation may again "wrap" the (new) seed with yet more + declarator stuff, by appending, prepending (or both). By the time the + recursion bottoms out, the "seed value" at that point will have a value + which is (almost) the complete source version of the declarator (except + for the data_type info). Thus, this deepest "seed" value is simply passed + back up through all of the recursive calls until it is given (as the return + value) to the initial caller of the gen_type() routine. All that remains + to do at this point is for the initial caller to prepend the "data_type" + string onto the returned "seed". */ + +static const char * +gen_type (const char *ret_val, tree t, formals_style style) +{ + tree chain_p; + + /* If there is a typedef name for this type, use it. */ + if (TYPE_NAME (t) && TREE_CODE (TYPE_NAME (t)) == TYPE_DECL) + data_type = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (t))); + else + { + switch (TREE_CODE (t)) + { + case POINTER_TYPE: + if (TYPE_READONLY (t)) + ret_val = concat ("const ", ret_val, NULL); + if (TYPE_VOLATILE (t)) + ret_val = concat ("volatile ", ret_val, NULL); + + ret_val = concat ("*", ret_val, NULL); + + if (TREE_CODE (TREE_TYPE (t)) == ARRAY_TYPE || TREE_CODE (TREE_TYPE (t)) == FUNCTION_TYPE) + ret_val = concat ("(", ret_val, ")", NULL); + + ret_val = gen_type (ret_val, TREE_TYPE (t), style); + + return ret_val; + + case ARRAY_TYPE: + if (!COMPLETE_TYPE_P (t) || TREE_CODE (TYPE_SIZE (t)) != INTEGER_CST) + ret_val = gen_type (concat (ret_val, "[]", NULL), + TREE_TYPE (t), style); + else if (int_size_in_bytes (t) == 0) + ret_val = gen_type (concat (ret_val, "[0]", NULL), + TREE_TYPE (t), style); + else + { + int size = (int_size_in_bytes (t) / int_size_in_bytes (TREE_TYPE (t))); + char buff[10]; + sprintf (buff, "[%d]", size); + ret_val = gen_type (concat (ret_val, buff, NULL), + TREE_TYPE (t), style); + } + break; + + case FUNCTION_TYPE: + ret_val = gen_type (concat (ret_val, + gen_formal_list_for_type (t, style), + NULL), + TREE_TYPE (t), style); + break; + + case IDENTIFIER_NODE: + data_type = IDENTIFIER_POINTER (t); + break; + + /* The following three cases are complicated by the fact that a + user may do something really stupid, like creating a brand new + "anonymous" type specification in a formal argument list (or as + part of a function return type specification). For example: + + int f (enum { red, green, blue } color); + + In such cases, we have no name that we can put into the prototype + to represent the (anonymous) type. Thus, we have to generate the + whole darn type specification. Yuck! */ + + case RECORD_TYPE: + if (TYPE_NAME (t)) + data_type = IDENTIFIER_POINTER (TYPE_NAME (t)); + else + { + data_type = ""; + chain_p = TYPE_FIELDS (t); + while (chain_p) + { + data_type = concat (data_type, gen_decl (chain_p, 0, ansi), + NULL); + chain_p = TREE_CHAIN (chain_p); + data_type = concat (data_type, "; ", NULL); + } + data_type = concat ("{ ", data_type, "}", NULL); + } + data_type = concat ("struct ", data_type, NULL); + break; + + case UNION_TYPE: + if (TYPE_NAME (t)) + data_type = IDENTIFIER_POINTER (TYPE_NAME (t)); + else + { + data_type = ""; + chain_p = TYPE_FIELDS (t); + while (chain_p) + { + data_type = concat (data_type, gen_decl (chain_p, 0, ansi), + NULL); + chain_p = TREE_CHAIN (chain_p); + data_type = concat (data_type, "; ", NULL); + } + data_type = concat ("{ ", data_type, "}", NULL); + } + data_type = concat ("union ", data_type, NULL); + break; + + case ENUMERAL_TYPE: + if (TYPE_NAME (t)) + data_type = IDENTIFIER_POINTER (TYPE_NAME (t)); + else + { + data_type = ""; + chain_p = TYPE_VALUES (t); + while (chain_p) + { + data_type = concat (data_type, + IDENTIFIER_POINTER (TREE_PURPOSE (chain_p)), NULL); + chain_p = TREE_CHAIN (chain_p); + if (chain_p) + data_type = concat (data_type, ", ", NULL); + } + data_type = concat ("{ ", data_type, " }", NULL); + } + data_type = concat ("enum ", data_type, NULL); + break; + + case TYPE_DECL: + data_type = IDENTIFIER_POINTER (DECL_NAME (t)); + break; + + case INTEGER_TYPE: + case FIXED_POINT_TYPE: + data_type = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (t))); + /* Normally, `unsigned' is part of the deal. Not so if it comes + with a type qualifier. */ + if (TYPE_UNSIGNED (t) && TYPE_QUALS (t)) + data_type = concat ("unsigned ", data_type, NULL); + break; + + case REAL_TYPE: + data_type = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (t))); + break; + + case VOID_TYPE: + data_type = "void"; + break; + + case ERROR_MARK: + data_type = "[ERROR]"; + break; + + default: + gcc_unreachable (); + } + } + if (TYPE_READONLY (t)) + ret_val = concat ("const ", ret_val, NULL); + if (TYPE_VOLATILE (t)) + ret_val = concat ("volatile ", ret_val, NULL); + if (TYPE_RESTRICT (t)) + ret_val = concat ("restrict ", ret_val, NULL); + return ret_val; +} + +/* Generate a string (source) representation of an entire entity declaration + (using some particular style for function types). + + The given entity may be either a variable or a function. + + If the "is_func_definition" parameter is nonzero, assume that the thing + we are generating a declaration for is a FUNCTION_DECL node which is + associated with a function definition. In this case, we can assume that + an attached list of DECL nodes for function formal arguments is present. */ + +static const char * +gen_decl (tree decl, int is_func_definition, formals_style style) +{ + const char *ret_val; + + if (DECL_NAME (decl)) + ret_val = IDENTIFIER_POINTER (DECL_NAME (decl)); + else + ret_val = ""; + + /* If we are just generating a list of names of formal parameters, we can + simply return the formal parameter name (with no typing information + attached to it) now. */ + + if (style == k_and_r_names) + return ret_val; + + /* Note that for the declaration of some entity (either a function or a + data object, like for instance a parameter) if the entity itself was + declared as either const or volatile, then const and volatile properties + are associated with just the declaration of the entity, and *not* with + the `type' of the entity. Thus, for such declared entities, we have to + generate the qualifiers here. */ + + if (TREE_THIS_VOLATILE (decl)) + ret_val = concat ("volatile ", ret_val, NULL); + if (TREE_READONLY (decl)) + ret_val = concat ("const ", ret_val, NULL); + + data_type = ""; + + /* For FUNCTION_DECL nodes, there are two possible cases here. First, if + this FUNCTION_DECL node was generated from a function "definition", then + we will have a list of DECL_NODE's, one for each of the function's formal + parameters. In this case, we can print out not only the types of each + formal, but also each formal's name. In the second case, this + FUNCTION_DECL node came from an actual function declaration (and *not* + a definition). In this case, we do nothing here because the formal + argument type-list will be output later, when the "type" of the function + is added to the string we are building. Note that the ANSI-style formal + parameter list is considered to be a (suffix) part of the "type" of the + function. */ + + if (TREE_CODE (decl) == FUNCTION_DECL && is_func_definition) + { + ret_val = concat (ret_val, gen_formal_list_for_func_def (decl, ansi), + NULL); + + /* Since we have already added in the formals list stuff, here we don't + add the whole "type" of the function we are considering (which + would include its parameter-list info), rather, we only add in + the "type" of the "type" of the function, which is really just + the return-type of the function (and does not include the parameter + list info). */ + + ret_val = gen_type (ret_val, TREE_TYPE (TREE_TYPE (decl)), style); + } + else + ret_val = gen_type (ret_val, TREE_TYPE (decl), style); + + ret_val = affix_data_type (ret_val); + + if (TREE_CODE (decl) != FUNCTION_DECL && C_DECL_REGISTER (decl)) + ret_val = concat ("register ", ret_val, NULL); + if (TREE_PUBLIC (decl)) + ret_val = concat ("extern ", ret_val, NULL); + if (TREE_CODE (decl) == FUNCTION_DECL && !TREE_PUBLIC (decl)) + ret_val = concat ("static ", ret_val, NULL); + + return ret_val; +} + +extern FILE *aux_info_file; + +/* Generate and write a new line of info to the aux-info (.X) file. This + routine is called once for each function declaration, and once for each + function definition (even the implicit ones). */ + +void +gen_aux_info_record (tree fndecl, int is_definition, int is_implicit, + int is_prototyped) +{ + if (flag_gen_aux_info) + { + static int compiled_from_record = 0; + expanded_location xloc = expand_location (DECL_SOURCE_LOCATION (fndecl)); + + /* Each output .X file must have a header line. Write one now if we + have not yet done so. */ + + if (!compiled_from_record++) + { + /* The first line tells which directory file names are relative to. + Currently, -aux-info works only for files in the working + directory, so just use a `.' as a placeholder for now. */ + fprintf (aux_info_file, "/* compiled from: . */\n"); + } + + /* Write the actual line of auxiliary info. */ + + fprintf (aux_info_file, "/* %s:%d:%c%c */ %s;", + xloc.file, xloc.line, + (is_implicit) ? 'I' : (is_prototyped) ? 'N' : 'O', + (is_definition) ? 'F' : 'C', + gen_decl (fndecl, is_definition, ansi)); + + /* If this is an explicit function declaration, we need to also write + out an old-style (i.e. K&R) function header, just in case the user + wants to run unprotoize. */ + + if (is_definition) + { + fprintf (aux_info_file, " /*%s %s*/", + gen_formal_list_for_func_def (fndecl, k_and_r_names), + gen_formal_list_for_func_def (fndecl, k_and_r_decls)); + } + + fprintf (aux_info_file, "\n"); + } +} diff --git a/gcc/c/c-convert.c b/gcc/c/c-convert.c new file mode 100644 index 00000000000..f4583c549c9 --- /dev/null +++ b/gcc/c/c-convert.c @@ -0,0 +1,183 @@ +/* Language-level data type conversion for GNU C. + Copyright (C) 1987, 1988, 1991, 1998, 2002, 2003, 2004, 2005, 2007, 2008, + 2009, 2010 Free Software Foundation, Inc. + +This file is part of GCC. + +GCC 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 3, or (at your option) any later +version. + +GCC 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 GCC; see the file COPYING3. If not see +<http://www.gnu.org/licenses/>. */ + + +/* This file contains the functions for converting C expressions + to different data types. The only entry point is `convert'. + Every language front end must have a `convert' function + but what kind of conversions it does will depend on the language. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "tm.h" +#include "tree.h" +#include "flags.h" +#include "convert.h" +#include "c-family/c-common.h" +#include "c-tree.h" +#include "langhooks.h" +#include "target.h" + +/* Change of width--truncation and extension of integers or reals-- + is represented with NOP_EXPR. Proper functioning of many things + assumes that no other conversions can be NOP_EXPRs. + + Conversion between integer and pointer is represented with CONVERT_EXPR. + Converting integer to real uses FLOAT_EXPR + and real to integer uses FIX_TRUNC_EXPR. + + Here is a list of all the functions that assume that widening and + narrowing is always done with a NOP_EXPR: + In convert.c, convert_to_integer. + In c-typeck.c, build_binary_op (boolean ops), and + c_common_truthvalue_conversion. + In expr.c: expand_expr, for operands of a MULT_EXPR. + In fold-const.c: fold. + In tree.c: get_narrower and get_unwidened. */ + +/* Subroutines of `convert'. */ + + + +/* Create an expression whose value is that of EXPR, + converted to type TYPE. The TREE_TYPE of the value + is always TYPE. This function implements all reasonable + conversions; callers should filter out those that are + not permitted by the language being compiled. */ + +tree +convert (tree type, tree expr) +{ + tree e = expr; + enum tree_code code = TREE_CODE (type); + const char *invalid_conv_diag; + tree ret; + location_t loc = EXPR_LOCATION (expr); + + if (type == error_mark_node + || expr == error_mark_node + || TREE_TYPE (expr) == error_mark_node) + return error_mark_node; + + if ((invalid_conv_diag + = targetm.invalid_conversion (TREE_TYPE (expr), type))) + { + error (invalid_conv_diag); + return error_mark_node; + } + + if (type == TREE_TYPE (expr)) + return expr; + ret = targetm.convert_to_type (type, expr); + if (ret) + return ret; + + STRIP_TYPE_NOPS (e); + + if (TYPE_MAIN_VARIANT (type) == TYPE_MAIN_VARIANT (TREE_TYPE (expr))) + return fold_convert_loc (loc, type, expr); + if (TREE_CODE (TREE_TYPE (expr)) == ERROR_MARK) + return error_mark_node; + if (TREE_CODE (TREE_TYPE (expr)) == VOID_TYPE) + { + error ("void value not ignored as it ought to be"); + return error_mark_node; + } + + switch (code) + { + case VOID_TYPE: + return fold_convert_loc (loc, type, e); + + case INTEGER_TYPE: + case ENUMERAL_TYPE: + ret = convert_to_integer (type, e); + goto maybe_fold; + + case BOOLEAN_TYPE: + return fold_convert_loc + (loc, type, c_objc_common_truthvalue_conversion (input_location, expr)); + + case POINTER_TYPE: + case REFERENCE_TYPE: + ret = convert_to_pointer (type, e); + goto maybe_fold; + + case REAL_TYPE: + ret = convert_to_real (type, e); + goto maybe_fold; + + case FIXED_POINT_TYPE: + ret = convert_to_fixed (type, e); + goto maybe_fold; + + case COMPLEX_TYPE: + /* If converting from COMPLEX_TYPE to a different COMPLEX_TYPE + and e is not COMPLEX_EXPR, convert_to_complex uses save_expr, + but for the C FE c_save_expr needs to be called instead. */ + if (TREE_CODE (TREE_TYPE (e)) == COMPLEX_TYPE) + { + tree subtype = TREE_TYPE (type); + tree elt_type = TREE_TYPE (TREE_TYPE (e)); + + if (TYPE_MAIN_VARIANT (elt_type) != TYPE_MAIN_VARIANT (subtype) + && TREE_CODE (e) != COMPLEX_EXPR) + { + if (in_late_binary_op) + e = save_expr (e); + else + e = c_save_expr (e); + ret + = fold_build2 (COMPLEX_EXPR, type, + convert (subtype, + fold_build1 (REALPART_EXPR, + elt_type, e)), + convert (subtype, + fold_build1 (IMAGPART_EXPR, + elt_type, e))); + goto maybe_fold; + } + } + ret = convert_to_complex (type, e); + goto maybe_fold; + + case VECTOR_TYPE: + ret = convert_to_vector (type, e); + goto maybe_fold; + + case RECORD_TYPE: + case UNION_TYPE: + if (lang_hooks.types_compatible_p (type, TREE_TYPE (expr))) + return e; + break; + + default: + break; + + maybe_fold: + if (TREE_CODE (ret) != C_MAYBE_CONST_EXPR) + ret = fold (ret); + return ret; + } + + error ("conversion to non-scalar type requested"); + return error_mark_node; +} diff --git a/gcc/c/c-decl.c b/gcc/c/c-decl.c new file mode 100644 index 00000000000..711b2dd1750 --- /dev/null +++ b/gcc/c/c-decl.c @@ -0,0 +1,10155 @@ +/* Process declarations and variables for C compiler. + Copyright (C) 1988, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, + 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012 + Free Software Foundation, Inc. + +This file is part of GCC. + +GCC 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 3, or (at your option) any later +version. + +GCC 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 GCC; see the file COPYING3. If not see +<http://www.gnu.org/licenses/>. */ + +/* 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. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "input.h" +#include "tm.h" +#include "intl.h" +#include "tree.h" +#include "tree-inline.h" +#include "flags.h" +#include "function.h" +#include "c-tree.h" +#include "toplev.h" +#include "tm_p.h" +#include "cpplib.h" +#include "target.h" +#include "debug.h" +#include "opts.h" +#include "timevar.h" +#include "c-family/c-common.h" +#include "c-family/c-objc.h" +#include "c-family/c-pragma.h" +#include "c-lang.h" +#include "langhooks.h" +#include "tree-iterator.h" +#include "diagnostic-core.h" +#include "tree-dump.h" +#include "cgraph.h" +#include "hashtab.h" +#include "langhooks-def.h" +#include "pointer-set.h" +#include "plugin.h" +#include "c-family/c-ada-spec.h" + +/* 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 */ + TYPENAME}; /* Typename (inside cast or sizeof) */ + +/* States indicating how grokdeclarator() should handle declspecs marked + with __attribute__((deprecated)). An object declared as + __attribute__((deprecated)) suppresses warnings of uses of other + deprecated items. */ + +enum deprecated_states { + DEPRECATED_NORMAL, + DEPRECATED_SUPPRESS +}; + + +/* 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. */ +location_t pending_invalid_xref_location; + +/* The file and line that the prototype came from if this is an + old-style definition; used for diagnostics in + store_parm_decls_oldstyle. */ + +static location_t current_function_prototype_locus; + +/* Whether this prototype was built-in. */ + +static bool current_function_prototype_built_in; + +/* The argument type information of this prototype. */ + +static tree current_function_prototype_arg_types; + +/* The argument information structure for the function currently being + defined. */ + +static struct c_arg_info *current_function_arg_info; + +/* The obstack on which parser and related data structures, which are + not live beyond their top-level declaration or definition, are + allocated. */ +struct obstack parser_obstack; + +/* The current statement tree. */ + +static GTY(()) struct stmt_tree_s c_stmt_tree; + +/* State saving variables. */ +tree c_break_label; +tree c_cont_label; + +/* A list of decls to be made automatically visible in each file scope. */ +static GTY(()) tree visible_builtins; + +/* 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 0 at beginning of a function definition, set to 1 if + a call to a noreturn function is seen. */ + +int current_function_returns_abnormally; + +/* 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 the current toplevel function contains a declaration + of a nested function which is never defined. */ + +static bool undef_nested_function; + +/* Mode used to build pointers (VOIDmode means ptr_mode). */ + +enum machine_mode c_default_pointer_mode = VOIDmode; + + +/* Each c_binding structure describes one binding of an identifier to + a decl. All the decls in a scope - irrespective of namespace - are + chained together by the ->prev field, which (as the name implies) + runs in reverse order. All the decls in a given namespace bound to + a given identifier are chained by the ->shadowed field, which runs + from inner to outer scopes. + + The ->decl field usually points to a DECL node, but there are two + exceptions. In the namespace of type tags, the bound entity is a + RECORD_TYPE, UNION_TYPE, or ENUMERAL_TYPE node. If an undeclared + identifier is encountered, it is bound to error_mark_node to + suppress further errors about that identifier in the current + function. + + The ->u.type field stores the type of the declaration in this scope; + if NULL, the type is the type of the ->decl field. This is only of + relevance for objects with external or internal linkage which may + be redeclared in inner scopes, forming composite types that only + persist for the duration of those scopes. In the external scope, + this stores the composite of all the types declared for this + object, visible or not. The ->inner_comp field (used only at file + scope) stores whether an incomplete array type at file scope was + completed at an inner scope to an array size other than 1. + + The ->u.label field is used for labels. It points to a structure + which stores additional information used for warnings. + + The depth field is copied from the scope structure that holds this + decl. It is used to preserve the proper ordering of the ->shadowed + field (see bind()) and also for a handful of special-case checks. + Finally, the invisible bit is true for a decl which should be + ignored for purposes of normal name lookup, and the nested bit is + true for a decl that's been bound a second time in an inner scope; + in all such cases, the binding in the outer scope will have its + invisible bit true. */ + +struct GTY((chain_next ("%h.prev"))) c_binding { + union GTY(()) { /* first so GTY desc can use decl */ + tree GTY((tag ("0"))) type; /* the type in this scope */ + struct c_label_vars * GTY((tag ("1"))) label; /* for warnings */ + } GTY((desc ("TREE_CODE (%0.decl) == LABEL_DECL"))) u; + tree decl; /* the decl bound */ + tree id; /* the identifier it's bound to */ + struct c_binding *prev; /* the previous decl in this scope */ + struct c_binding *shadowed; /* the innermost decl shadowed by this one */ + unsigned int depth : 28; /* depth of this scope */ + BOOL_BITFIELD invisible : 1; /* normal lookup should ignore this binding */ + BOOL_BITFIELD nested : 1; /* do not set DECL_CONTEXT when popping */ + BOOL_BITFIELD inner_comp : 1; /* incomplete array completed in inner scope */ + BOOL_BITFIELD in_struct : 1; /* currently defined as struct field */ + location_t locus; /* location for nested bindings */ +}; +#define B_IN_SCOPE(b1, b2) ((b1)->depth == (b2)->depth) +#define B_IN_CURRENT_SCOPE(b) ((b)->depth == current_scope->depth) +#define B_IN_FILE_SCOPE(b) ((b)->depth == 1 /*file_scope->depth*/) +#define B_IN_EXTERNAL_SCOPE(b) ((b)->depth == 0 /*external_scope->depth*/) + +#define I_SYMBOL_BINDING(node) \ + (((struct lang_identifier *) IDENTIFIER_NODE_CHECK(node))->symbol_binding) +#define I_SYMBOL_DECL(node) \ + (I_SYMBOL_BINDING(node) ? I_SYMBOL_BINDING(node)->decl : 0) + +#define I_TAG_BINDING(node) \ + (((struct lang_identifier *) IDENTIFIER_NODE_CHECK(node))->tag_binding) +#define I_TAG_DECL(node) \ + (I_TAG_BINDING(node) ? I_TAG_BINDING(node)->decl : 0) + +#define I_LABEL_BINDING(node) \ + (((struct lang_identifier *) IDENTIFIER_NODE_CHECK(node))->label_binding) +#define I_LABEL_DECL(node) \ + (I_LABEL_BINDING(node) ? I_LABEL_BINDING(node)->decl : 0) + +/* Each C symbol points to three linked lists of c_binding structures. + These describe the values of the identifier in the three different + namespaces defined by the language. */ + +struct GTY(()) lang_identifier { + struct c_common_identifier common_id; + struct c_binding *symbol_binding; /* vars, funcs, constants, typedefs */ + struct c_binding *tag_binding; /* struct/union/enum tags */ + struct c_binding *label_binding; /* labels */ +}; + +/* Validate c-lang.c's assumptions. */ +extern char C_SIZEOF_STRUCT_LANG_IDENTIFIER_isnt_accurate +[(sizeof(struct lang_identifier) == C_SIZEOF_STRUCT_LANG_IDENTIFIER) ? 1 : -1]; + +/* The resulting tree type. */ + +union GTY((desc ("TREE_CODE (&%h.generic) == IDENTIFIER_NODE"), + chain_next ("(union lang_tree_node *) c_tree_chain_next (&%h.generic)"))) lang_tree_node + { + union tree_node GTY ((tag ("0"), + desc ("tree_node_structure (&%h)"))) + generic; + struct lang_identifier GTY ((tag ("1"))) identifier; +}; + +/* Track bindings and other things that matter for goto warnings. For + efficiency, we do not gather all the decls at the point of + definition. Instead, we point into the bindings structure. As + scopes are popped, we update these structures and gather the decls + that matter at that time. */ + +struct GTY(()) c_spot_bindings { + /* The currently open scope which holds bindings defined when the + label was defined or the goto statement was found. */ + struct c_scope *scope; + /* The bindings in the scope field which were defined at the point + of the label or goto. This lets us look at older or newer + bindings in the scope, as appropriate. */ + struct c_binding *bindings_in_scope; + /* The number of statement expressions that have started since this + label or goto statement was defined. This is zero if we are at + the same statement expression level. It is positive if we are in + a statement expression started since this spot. It is negative + if this spot was in a statement expression and we have left + it. */ + int stmt_exprs; + /* Whether we started in a statement expression but are no longer in + it. This is set to true if stmt_exprs ever goes negative. */ + bool left_stmt_expr; +}; + +/* This structure is used to keep track of bindings seen when a goto + statement is defined. This is only used if we see the goto + statement before we see the label. */ + +struct GTY(()) c_goto_bindings { + /* The location of the goto statement. */ + location_t loc; + /* The bindings of the goto statement. */ + struct c_spot_bindings goto_bindings; +}; + +typedef struct c_goto_bindings *c_goto_bindings_p; +DEF_VEC_P(c_goto_bindings_p); +DEF_VEC_ALLOC_P(c_goto_bindings_p,gc); + +/* The additional information we keep track of for a label binding. + These fields are updated as scopes are popped. */ + +struct GTY(()) c_label_vars { + /* The shadowed c_label_vars, when one label shadows another (which + can only happen using a __label__ declaration). */ + struct c_label_vars *shadowed; + /* The bindings when the label was defined. */ + struct c_spot_bindings label_bindings; + /* A list of decls that we care about: decls about which we should + warn if a goto branches to this label from later in the function. + Decls are added to this list as scopes are popped. We only add + the decls that matter. */ + VEC(tree,gc) *decls_in_scope; + /* A list of goto statements to this label. This is only used for + goto statements seen before the label was defined, so that we can + issue appropriate warnings for them. */ + VEC(c_goto_bindings_p,gc) *gotos; +}; + +/* Each c_scope structure describes the complete contents of one + scope. Four scopes are distinguished specially: the innermost or + current scope, the innermost function scope, the file scope (always + the second to outermost) and the outermost or external scope. + + Most declarations are recorded in the current scope. + + All normal label declarations are recorded in the innermost + function scope, as are bindings of undeclared identifiers to + error_mark_node. (GCC permits nested functions as an extension, + hence the 'innermost' qualifier.) Explicitly declared labels + (using the __label__ extension) appear in the current scope. + + Being in the file scope (current_scope == file_scope) causes + special behavior in several places below. Also, under some + conditions the Objective-C front end records declarations in the + file scope even though that isn't the current scope. + + All declarations with external linkage are recorded in the external + scope, even if they aren't visible there; this models the fact that + such declarations are visible to the entire program, and (with a + bit of cleverness, see pushdecl) allows diagnosis of some violations + of C99 6.2.2p7 and 6.2.7p2: + + If, within the same translation unit, the same identifier appears + with both internal and external linkage, the behavior is + undefined. + + All declarations that refer to the same object or function shall + have compatible type; otherwise, the behavior is undefined. + + Initially only the built-in declarations, which describe compiler + intrinsic functions plus a subset of the standard library, are in + this scope. + + The order of the blocks list matters, and it is frequently appended + to. To avoid having to walk all the way to the end of the list on + each insertion, or reverse the list later, we maintain a pointer to + the last list entry. (FIXME: It should be feasible to use a reversed + list here.) + + The bindings list is strictly in reverse order of declarations; + pop_scope relies on this. */ + + +struct GTY((chain_next ("%h.outer"))) c_scope { + /* The scope containing this one. */ + struct c_scope *outer; + + /* The next outermost function scope. */ + struct c_scope *outer_function; + + /* All bindings in this scope. */ + struct c_binding *bindings; + + /* For each scope (except the global one), a chain of BLOCK nodes + for all the scopes that were entered and exited one level down. */ + tree blocks; + tree blocks_last; + + /* The depth of this scope. Used to keep the ->shadowed chain of + bindings sorted innermost to outermost. */ + unsigned int depth : 28; + + /* True if we are currently filling this scope with parameter + declarations. */ + BOOL_BITFIELD parm_flag : 1; + + /* True if we saw [*] in this scope. Used to give an error messages + if these appears in a function definition. */ + BOOL_BITFIELD had_vla_unspec : 1; + + /* True if we already complained about forward parameter decls + in this scope. This prevents double warnings on + foo (int a; int b; ...) */ + BOOL_BITFIELD warned_forward_parm_decls : 1; + + /* True if this is the outermost block scope of a function body. + This scope contains the parameters, the local variables declared + in the outermost block, and all the labels (except those in + nested functions, or declared at block scope with __label__). */ + BOOL_BITFIELD function_body : 1; + + /* True means make a BLOCK for this scope no matter what. */ + BOOL_BITFIELD keep : 1; + + /* True means that an unsuffixed float constant is _Decimal64. */ + BOOL_BITFIELD float_const_decimal64 : 1; + + /* True if this scope has any label bindings. This is used to speed + up searching for labels when popping scopes, particularly since + labels are normally only found at function scope. */ + BOOL_BITFIELD has_label_bindings : 1; + + /* True if we should issue a warning if a goto statement crosses any + of the bindings. We still need to check the list of bindings to + find the specific ones we need to warn about. This is true if + decl_jump_unsafe would return true for any of the bindings. This + is used to avoid looping over all the bindings unnecessarily. */ + BOOL_BITFIELD has_jump_unsafe_decl : 1; +}; + +/* The scope currently in effect. */ + +static GTY(()) struct c_scope *current_scope; + +/* The innermost function scope. Ordinary (not explicitly declared) + labels, bindings to error_mark_node, and the lazily-created + bindings of __func__ and its friends get this scope. */ + +static GTY(()) struct c_scope *current_function_scope; + +/* The C file scope. This is reset for each input translation unit. */ + +static GTY(()) struct c_scope *file_scope; + +/* The outermost scope. This is used for all declarations with + external linkage, and only these, hence the name. */ + +static GTY(()) struct c_scope *external_scope; + +/* A chain of c_scope structures awaiting reuse. */ + +static GTY((deletable)) struct c_scope *scope_freelist; + +/* A chain of c_binding structures awaiting reuse. */ + +static GTY((deletable)) struct c_binding *binding_freelist; + +/* Append VAR to LIST in scope SCOPE. */ +#define SCOPE_LIST_APPEND(scope, list, decl) do { \ + struct c_scope *s_ = (scope); \ + tree d_ = (decl); \ + if (s_->list##_last) \ + BLOCK_CHAIN (s_->list##_last) = d_; \ + else \ + s_->list = d_; \ + s_->list##_last = d_; \ +} while (0) + +/* Concatenate FROM in scope FSCOPE onto TO in scope TSCOPE. */ +#define SCOPE_LIST_CONCAT(tscope, to, fscope, from) do { \ + struct c_scope *t_ = (tscope); \ + struct c_scope *f_ = (fscope); \ + if (t_->to##_last) \ + BLOCK_CHAIN (t_->to##_last) = f_->from; \ + else \ + t_->to = f_->from; \ + t_->to##_last = f_->from##_last; \ +} while (0) + +/* A c_inline_static structure stores details of a static identifier + referenced in a definition of a function that may be an inline + definition if no subsequent declaration of that function uses + "extern" or does not use "inline". */ + +struct GTY((chain_next ("%h.next"))) c_inline_static { + /* The location for a diagnostic. */ + location_t location; + + /* The function that may be an inline definition. */ + tree function; + + /* The object or function referenced. */ + tree static_decl; + + /* What sort of reference this is. */ + enum c_inline_static_type type; + + /* The next such structure or NULL. */ + struct c_inline_static *next; +}; + +/* List of static identifiers used or referenced in functions that may + be inline definitions. */ +static GTY(()) struct c_inline_static *c_inline_statics; + +/* True means unconditionally make a BLOCK for the next scope pushed. */ + +static bool keep_next_level_flag; + +/* True means the next call to push_scope will be the outermost scope + of a function body, so do not push a new scope, merely cease + expecting parameter decls. */ + +static bool next_is_function_body; + +/* A VEC of pointers to c_binding structures. */ + +typedef struct c_binding *c_binding_ptr; +DEF_VEC_P(c_binding_ptr); +DEF_VEC_ALLOC_P(c_binding_ptr,heap); + +/* Information that we keep for a struct or union while it is being + parsed. */ + +struct c_struct_parse_info +{ + /* If warn_cxx_compat, a list of types defined within this + struct. */ + VEC(tree,heap) *struct_types; + /* If warn_cxx_compat, a list of field names which have bindings, + and which are defined in this struct, but which are not defined + in any enclosing struct. This is used to clear the in_struct + field of the c_bindings structure. */ + VEC(c_binding_ptr,heap) *fields; + /* If warn_cxx_compat, a list of typedef names used when defining + fields in this struct. */ + VEC(tree,heap) *typedefs_seen; +}; + +/* Information for the struct or union currently being parsed, or + NULL if not parsing a struct or union. */ +static struct c_struct_parse_info *struct_parse_info; + +/* Forward declarations. */ +static tree lookup_name_in_scope (tree, struct c_scope *); +static tree c_make_fname_decl (location_t, tree, int); +static tree grokdeclarator (const struct c_declarator *, + struct c_declspecs *, + enum decl_context, bool, tree *, tree *, tree *, + bool *, enum deprecated_states); +static tree grokparms (struct c_arg_info *, bool); +static void layout_array_type (tree); + +/* T is a statement. Add it to the statement-tree. This is the + C/ObjC version--C++ has a slightly different version of this + function. */ + +tree +add_stmt (tree t) +{ + enum tree_code code = TREE_CODE (t); + + if (CAN_HAVE_LOCATION_P (t) && code != LABEL_EXPR) + { + if (!EXPR_HAS_LOCATION (t)) + SET_EXPR_LOCATION (t, input_location); + } + + if (code == LABEL_EXPR || code == CASE_LABEL_EXPR) + STATEMENT_LIST_HAS_LABEL (cur_stmt_list) = 1; + + /* Add T to the statement-tree. Non-side-effect statements need to be + recorded during statement expressions. */ + if (!building_stmt_list_p ()) + push_stmt_list (); + append_to_statement_list_force (t, &cur_stmt_list); + + return t; +} + +/* Build a pointer type using the default pointer mode. */ + +static tree +c_build_pointer_type (tree to_type) +{ + addr_space_t as = to_type == error_mark_node? ADDR_SPACE_GENERIC + : TYPE_ADDR_SPACE (to_type); + enum machine_mode pointer_mode; + + if (as != ADDR_SPACE_GENERIC || c_default_pointer_mode == VOIDmode) + pointer_mode = targetm.addr_space.pointer_mode (as); + else + pointer_mode = c_default_pointer_mode; + return build_pointer_type_for_mode (to_type, pointer_mode, false); +} + + +/* Return true if we will want to say something if a goto statement + crosses DECL. */ + +static bool +decl_jump_unsafe (tree decl) +{ + if (error_operand_p (decl)) + return false; + + /* Always warn about crossing variably modified types. */ + if ((TREE_CODE (decl) == VAR_DECL || TREE_CODE (decl) == TYPE_DECL) + && variably_modified_type_p (TREE_TYPE (decl), NULL_TREE)) + return true; + + /* Otherwise, only warn if -Wgoto-misses-init and this is an + initialized automatic decl. */ + if (warn_jump_misses_init + && TREE_CODE (decl) == VAR_DECL + && !TREE_STATIC (decl) + && DECL_INITIAL (decl) != NULL_TREE) + return true; + + return false; +} + + +void +c_print_identifier (FILE *file, tree node, int indent) +{ + print_node (file, "symbol", I_SYMBOL_DECL (node), indent + 4); + print_node (file, "tag", I_TAG_DECL (node), indent + 4); + print_node (file, "label", I_LABEL_DECL (node), indent + 4); + if (C_IS_RESERVED_WORD (node) && C_RID_CODE (node) != RID_CXX_COMPAT_WARN) + { + tree rid = ridpointers[C_RID_CODE (node)]; + indent_to (file, indent + 4); + fprintf (file, "rid " HOST_PTR_PRINTF " \"%s\"", + (void *) rid, IDENTIFIER_POINTER (rid)); + } +} + +/* Establish a binding between NAME, an IDENTIFIER_NODE, and DECL, + which may be any of several kinds of DECL or TYPE or error_mark_node, + in the scope SCOPE. */ +static void +bind (tree name, tree decl, struct c_scope *scope, bool invisible, + bool nested, location_t locus) +{ + struct c_binding *b, **here; + + if (binding_freelist) + { + b = binding_freelist; + binding_freelist = b->prev; + } + else + b = ggc_alloc_c_binding (); + + b->shadowed = 0; + b->decl = decl; + b->id = name; + b->depth = scope->depth; + b->invisible = invisible; + b->nested = nested; + b->inner_comp = 0; + b->in_struct = 0; + b->locus = locus; + + b->u.type = NULL; + + b->prev = scope->bindings; + scope->bindings = b; + + if (decl_jump_unsafe (decl)) + scope->has_jump_unsafe_decl = 1; + + if (!name) + return; + + switch (TREE_CODE (decl)) + { + case LABEL_DECL: here = &I_LABEL_BINDING (name); break; + case ENUMERAL_TYPE: + case UNION_TYPE: + case RECORD_TYPE: here = &I_TAG_BINDING (name); break; + case VAR_DECL: + case FUNCTION_DECL: + case TYPE_DECL: + case CONST_DECL: + case PARM_DECL: + case ERROR_MARK: here = &I_SYMBOL_BINDING (name); break; + + default: + gcc_unreachable (); + } + + /* Locate the appropriate place in the chain of shadowed decls + to insert this binding. Normally, scope == current_scope and + this does nothing. */ + while (*here && (*here)->depth > scope->depth) + here = &(*here)->shadowed; + + b->shadowed = *here; + *here = b; +} + +/* Clear the binding structure B, stick it on the binding_freelist, + and return the former value of b->prev. This is used by pop_scope + and get_parm_info to iterate destructively over all the bindings + from a given scope. */ +static struct c_binding * +free_binding_and_advance (struct c_binding *b) +{ + struct c_binding *prev = b->prev; + + memset (b, 0, sizeof (struct c_binding)); + b->prev = binding_freelist; + binding_freelist = b; + + return prev; +} + +/* Bind a label. Like bind, but skip fields which aren't used for + labels, and add the LABEL_VARS value. */ +static void +bind_label (tree name, tree label, struct c_scope *scope, + struct c_label_vars *label_vars) +{ + struct c_binding *b; + + bind (name, label, scope, /*invisible=*/false, /*nested=*/false, + UNKNOWN_LOCATION); + + scope->has_label_bindings = true; + + b = scope->bindings; + gcc_assert (b->decl == label); + label_vars->shadowed = b->u.label; + b->u.label = label_vars; +} + +/* Hook called at end of compilation to assume 1 elt + for a file-scope tentative array defn that wasn't complete before. */ + +void +c_finish_incomplete_decl (tree decl) +{ + if (TREE_CODE (decl) == VAR_DECL) + { + tree type = TREE_TYPE (decl); + if (type != error_mark_node + && TREE_CODE (type) == ARRAY_TYPE + && !DECL_EXTERNAL (decl) + && TYPE_DOMAIN (type) == 0) + { + warning_at (DECL_SOURCE_LOCATION (decl), + 0, "array %q+D assumed to have one element", decl); + + complete_array_type (&TREE_TYPE (decl), NULL_TREE, true); + + relayout_decl (decl); + } + } +} + +/* Record that inline function FUNC contains a reference (location + LOC) to static DECL (file-scope or function-local according to + TYPE). */ + +void +record_inline_static (location_t loc, tree func, tree decl, + enum c_inline_static_type type) +{ + struct c_inline_static *csi = ggc_alloc_c_inline_static (); + csi->location = loc; + csi->function = func; + csi->static_decl = decl; + csi->type = type; + csi->next = c_inline_statics; + c_inline_statics = csi; +} + +/* Check for references to static declarations in inline functions at + the end of the translation unit and diagnose them if the functions + are still inline definitions. */ + +static void +check_inline_statics (void) +{ + struct c_inline_static *csi; + for (csi = c_inline_statics; csi; csi = csi->next) + { + if (DECL_EXTERNAL (csi->function)) + switch (csi->type) + { + case csi_internal: + pedwarn (csi->location, 0, + "%qD is static but used in inline function %qD " + "which is not static", csi->static_decl, csi->function); + break; + case csi_modifiable: + pedwarn (csi->location, 0, + "%q+D is static but declared in inline function %qD " + "which is not static", csi->static_decl, csi->function); + break; + default: + gcc_unreachable (); + } + } + c_inline_statics = NULL; +} + +/* Fill in a c_spot_bindings structure. If DEFINING is true, set it + for the current state, otherwise set it to uninitialized. */ + +static void +set_spot_bindings (struct c_spot_bindings *p, bool defining) +{ + if (defining) + { + p->scope = current_scope; + p->bindings_in_scope = current_scope->bindings; + } + else + { + p->scope = NULL; + p->bindings_in_scope = NULL; + } + p->stmt_exprs = 0; + p->left_stmt_expr = false; +} + +/* Update spot bindings P as we pop out of SCOPE. Return true if we + should push decls for a label. */ + +static bool +update_spot_bindings (struct c_scope *scope, struct c_spot_bindings *p) +{ + if (p->scope != scope) + { + /* This label or goto is defined in some other scope, or it is a + label which is not yet defined. There is nothing to + update. */ + return false; + } + + /* Adjust the spot bindings to refer to the bindings already defined + in the enclosing scope. */ + p->scope = scope->outer; + p->bindings_in_scope = p->scope->bindings; + + return true; +} + +/* The Objective-C front-end often needs to determine the current scope. */ + +void * +objc_get_current_scope (void) +{ + return current_scope; +} + +/* The following function is used only by Objective-C. It needs to live here + because it accesses the innards of c_scope. */ + +void +objc_mark_locals_volatile (void *enclosing_blk) +{ + struct c_scope *scope; + struct c_binding *b; + + for (scope = current_scope; + scope && scope != enclosing_blk; + scope = scope->outer) + { + for (b = scope->bindings; b; b = b->prev) + objc_volatilize_decl (b->decl); + + /* Do not climb up past the current function. */ + if (scope->function_body) + break; + } +} + +/* Return true if we are in the global binding level. */ + +bool +global_bindings_p (void) +{ + return current_scope == file_scope; +} + +void +keep_next_level (void) +{ + keep_next_level_flag = true; +} + +/* Set the flag for the FLOAT_CONST_DECIMAL64 pragma being ON. */ + +void +set_float_const_decimal64 (void) +{ + current_scope->float_const_decimal64 = true; +} + +/* Clear the flag for the FLOAT_CONST_DECIMAL64 pragma. */ + +void +clear_float_const_decimal64 (void) +{ + current_scope->float_const_decimal64 = false; +} + +/* Return nonzero if an unsuffixed float constant is _Decimal64. */ + +bool +float_const_decimal64_p (void) +{ + return current_scope->float_const_decimal64; +} + +/* Identify this scope as currently being filled with parameters. */ + +void +declare_parm_level (void) +{ + current_scope->parm_flag = true; +} + +void +push_scope (void) +{ + if (next_is_function_body) + { + /* This is the transition from the parameters to the top level + of the function body. These are the same scope + (C99 6.2.1p4,6) so we do not push another scope structure. + next_is_function_body is set only by store_parm_decls, which + in turn is called when and only when we are about to + encounter the opening curly brace for the function body. + + The outermost block of a function always gets a BLOCK node, + because the debugging output routines expect that each + function has at least one BLOCK. */ + current_scope->parm_flag = false; + current_scope->function_body = true; + current_scope->keep = true; + current_scope->outer_function = current_function_scope; + current_function_scope = current_scope; + + keep_next_level_flag = false; + next_is_function_body = false; + + /* The FLOAT_CONST_DECIMAL64 pragma applies to nested scopes. */ + if (current_scope->outer) + current_scope->float_const_decimal64 + = current_scope->outer->float_const_decimal64; + else + current_scope->float_const_decimal64 = false; + } + else + { + struct c_scope *scope; + if (scope_freelist) + { + scope = scope_freelist; + scope_freelist = scope->outer; + } + else + scope = ggc_alloc_cleared_c_scope (); + + /* The FLOAT_CONST_DECIMAL64 pragma applies to nested scopes. */ + if (current_scope) + scope->float_const_decimal64 = current_scope->float_const_decimal64; + else + scope->float_const_decimal64 = false; + + scope->keep = keep_next_level_flag; + scope->outer = current_scope; + scope->depth = current_scope ? (current_scope->depth + 1) : 0; + + /* Check for scope depth overflow. Unlikely (2^28 == 268,435,456) but + possible. */ + if (current_scope && scope->depth == 0) + { + scope->depth--; + sorry ("GCC supports only %u nested scopes", scope->depth); + } + + current_scope = scope; + keep_next_level_flag = false; + } +} + +/* This is called when we are leaving SCOPE. For each label defined + in SCOPE, add any appropriate decls to its decls_in_scope fields. + These are the decls whose initialization will be skipped by a goto + later in the function. */ + +static void +update_label_decls (struct c_scope *scope) +{ + struct c_scope *s; + + s = scope; + while (s != NULL) + { + if (s->has_label_bindings) + { + struct c_binding *b; + + for (b = s->bindings; b != NULL; b = b->prev) + { + struct c_label_vars *label_vars; + struct c_binding *b1; + bool hjud; + unsigned int ix; + struct c_goto_bindings *g; + + if (TREE_CODE (b->decl) != LABEL_DECL) + continue; + label_vars = b->u.label; + + b1 = label_vars->label_bindings.bindings_in_scope; + if (label_vars->label_bindings.scope == NULL) + hjud = false; + else + hjud = label_vars->label_bindings.scope->has_jump_unsafe_decl; + if (update_spot_bindings (scope, &label_vars->label_bindings)) + { + /* This label is defined in this scope. */ + if (hjud) + { + for (; b1 != NULL; b1 = b1->prev) + { + /* A goto from later in the function to this + label will never see the initialization + of B1, if any. Save it to issue a + warning if needed. */ + if (decl_jump_unsafe (b1->decl)) + VEC_safe_push (tree, gc, + label_vars->decls_in_scope, + b1->decl); + } + } + } + + /* Update the bindings of any goto statements associated + with this label. */ + FOR_EACH_VEC_ELT (c_goto_bindings_p, label_vars->gotos, ix, g) + update_spot_bindings (scope, &g->goto_bindings); + } + } + + /* Don't search beyond the current function. */ + if (s == current_function_scope) + break; + + s = s->outer; + } +} + +/* Set the TYPE_CONTEXT of all of TYPE's variants to CONTEXT. */ + +static void +set_type_context (tree type, tree context) +{ + for (type = TYPE_MAIN_VARIANT (type); type; + type = TYPE_NEXT_VARIANT (type)) + TYPE_CONTEXT (type) = context; +} + +/* Exit a scope. Restore the state of the identifier-decl mappings + that were in effect when this scope was entered. Return a BLOCK + node containing all the DECLs in this scope that are of interest + to debug info generation. */ + +tree +pop_scope (void) +{ + struct c_scope *scope = current_scope; + tree block, context, p; + struct c_binding *b; + + bool functionbody = scope->function_body; + bool keep = functionbody || scope->keep || scope->bindings; + + update_label_decls (scope); + + /* If appropriate, create a BLOCK to record the decls for the life + of this function. */ + block = 0; + if (keep) + { + block = make_node (BLOCK); + BLOCK_SUBBLOCKS (block) = scope->blocks; + TREE_USED (block) = 1; + + /* In each subblock, record that this is its superior. */ + for (p = scope->blocks; p; p = BLOCK_CHAIN (p)) + BLOCK_SUPERCONTEXT (p) = block; + + BLOCK_VARS (block) = 0; + } + + /* The TYPE_CONTEXTs for all of the tagged types belonging to this + scope must be set 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 (scope->function_body) + context = current_function_decl; + else if (scope == file_scope) + { + tree file_decl = build_translation_unit_decl (NULL_TREE); + context = file_decl; + } + else + context = block; + + /* Clear all bindings in this scope. */ + for (b = scope->bindings; b; b = free_binding_and_advance (b)) + { + p = b->decl; + switch (TREE_CODE (p)) + { + case LABEL_DECL: + /* Warnings for unused labels, errors for undefined labels. */ + if (TREE_USED (p) && !DECL_INITIAL (p)) + { + error ("label %q+D used but not defined", p); + DECL_INITIAL (p) = error_mark_node; + } + else + warn_for_unused_label (p); + + /* Labels go in BLOCK_VARS. */ + DECL_CHAIN (p) = BLOCK_VARS (block); + BLOCK_VARS (block) = p; + gcc_assert (I_LABEL_BINDING (b->id) == b); + I_LABEL_BINDING (b->id) = b->shadowed; + + /* Also pop back to the shadowed label_vars. */ + release_tree_vector (b->u.label->decls_in_scope); + b->u.label = b->u.label->shadowed; + break; + + case ENUMERAL_TYPE: + case UNION_TYPE: + case RECORD_TYPE: + set_type_context (p, context); + + /* Types may not have tag-names, in which case the type + appears in the bindings list with b->id NULL. */ + if (b->id) + { + gcc_assert (I_TAG_BINDING (b->id) == b); + I_TAG_BINDING (b->id) = b->shadowed; + } + break; + + case FUNCTION_DECL: + /* Propagate TREE_ADDRESSABLE from nested functions to their + containing functions. */ + if (!TREE_ASM_WRITTEN (p) + && DECL_INITIAL (p) != 0 + && TREE_ADDRESSABLE (p) + && DECL_ABSTRACT_ORIGIN (p) != 0 + && DECL_ABSTRACT_ORIGIN (p) != p) + TREE_ADDRESSABLE (DECL_ABSTRACT_ORIGIN (p)) = 1; + if (!DECL_EXTERNAL (p) + && !DECL_INITIAL (p) + && scope != file_scope + && scope != external_scope) + { + error ("nested function %q+D declared but never defined", p); + undef_nested_function = true; + } + else if (DECL_DECLARED_INLINE_P (p) + && TREE_PUBLIC (p) + && !DECL_INITIAL (p)) + { + /* C99 6.7.4p6: "a function with external linkage... declared + with an inline function specifier ... shall also be defined + in the same translation unit." */ + if (!flag_gnu89_inline) + pedwarn (input_location, 0, + "inline function %q+D declared but never defined", p); + DECL_EXTERNAL (p) = 1; + } + + goto common_symbol; + + case VAR_DECL: + /* Warnings for unused variables. */ + if ((!TREE_USED (p) || !DECL_READ_P (p)) + && !TREE_NO_WARNING (p) + && !DECL_IN_SYSTEM_HEADER (p) + && DECL_NAME (p) + && !DECL_ARTIFICIAL (p) + && scope != file_scope + && scope != external_scope) + { + if (!TREE_USED (p)) + warning (OPT_Wunused_variable, "unused variable %q+D", p); + else if (DECL_CONTEXT (p) == current_function_decl) + warning_at (DECL_SOURCE_LOCATION (p), + OPT_Wunused_but_set_variable, + "variable %qD set but not used", p); + } + + if (b->inner_comp) + { + error ("type of array %q+D completed incompatibly with" + " implicit initialization", p); + } + + /* Fall through. */ + case TYPE_DECL: + case CONST_DECL: + common_symbol: + /* All of these go in BLOCK_VARS, but only if this is the + binding in the home scope. */ + if (!b->nested) + { + DECL_CHAIN (p) = BLOCK_VARS (block); + BLOCK_VARS (block) = p; + } + else if (VAR_OR_FUNCTION_DECL_P (p) && scope != file_scope) + { + /* For block local externs add a special + DECL_EXTERNAL decl for debug info generation. */ + tree extp = copy_node (p); + + DECL_EXTERNAL (extp) = 1; + TREE_STATIC (extp) = 0; + TREE_PUBLIC (extp) = 1; + DECL_INITIAL (extp) = NULL_TREE; + DECL_LANG_SPECIFIC (extp) = NULL; + DECL_CONTEXT (extp) = current_function_decl; + if (TREE_CODE (p) == FUNCTION_DECL) + { + DECL_RESULT (extp) = NULL_TREE; + DECL_SAVED_TREE (extp) = NULL_TREE; + DECL_STRUCT_FUNCTION (extp) = NULL; + } + if (b->locus != UNKNOWN_LOCATION) + DECL_SOURCE_LOCATION (extp) = b->locus; + DECL_CHAIN (extp) = BLOCK_VARS (block); + BLOCK_VARS (block) = extp; + } + /* If this is the file scope set DECL_CONTEXT of each decl to + the TRANSLATION_UNIT_DECL. This makes same_translation_unit_p + work. */ + if (scope == file_scope) + { + DECL_CONTEXT (p) = context; + if (TREE_CODE (p) == TYPE_DECL + && TREE_TYPE (p) != error_mark_node) + set_type_context (TREE_TYPE (p), context); + } + + /* Fall through. */ + /* Parameters go in DECL_ARGUMENTS, not BLOCK_VARS, and have + already been put there by store_parm_decls. Unused- + parameter warnings are handled by function.c. + error_mark_node obviously does not go in BLOCK_VARS and + does not get unused-variable warnings. */ + case PARM_DECL: + case ERROR_MARK: + /* It is possible for a decl not to have a name. We get + here with b->id NULL in this case. */ + if (b->id) + { + gcc_assert (I_SYMBOL_BINDING (b->id) == b); + I_SYMBOL_BINDING (b->id) = b->shadowed; + if (b->shadowed && b->shadowed->u.type) + TREE_TYPE (b->shadowed->decl) = b->shadowed->u.type; + } + break; + + default: + gcc_unreachable (); + } + } + + + /* Dispose of the block that we just made inside some higher level. */ + if ((scope->function_body || scope == file_scope) && context) + { + DECL_INITIAL (context) = block; + BLOCK_SUPERCONTEXT (block) = context; + } + else if (scope->outer) + { + if (block) + SCOPE_LIST_APPEND (scope->outer, blocks, block); + /* If we did not make a block for the scope just exited, any + blocks made for inner scopes must be carried forward so they + will later become subblocks of something else. */ + else if (scope->blocks) + SCOPE_LIST_CONCAT (scope->outer, blocks, scope, blocks); + } + + /* Pop the current scope, and free the structure for reuse. */ + current_scope = scope->outer; + if (scope->function_body) + current_function_scope = scope->outer_function; + + memset (scope, 0, sizeof (struct c_scope)); + scope->outer = scope_freelist; + scope_freelist = scope; + + return block; +} + +void +push_file_scope (void) +{ + tree decl; + + if (file_scope) + return; + + push_scope (); + file_scope = current_scope; + + start_fname_decls (); + + for (decl = visible_builtins; decl; decl = DECL_CHAIN (decl)) + bind (DECL_NAME (decl), decl, file_scope, + /*invisible=*/false, /*nested=*/true, DECL_SOURCE_LOCATION (decl)); +} + +void +pop_file_scope (void) +{ + /* In case there were missing closebraces, get us back to the global + binding level. */ + while (current_scope != file_scope) + pop_scope (); + + /* __FUNCTION__ is defined at file scope (""). This + call may not be necessary as my tests indicate it + still works without it. */ + finish_fname_decls (); + + check_inline_statics (); + + /* This is the point to write out a PCH if we're doing that. + In that case we do not want to do anything else. */ + if (pch_file) + { + c_common_write_pch (); + return; + } + + /* Pop off the file scope and close this translation unit. */ + pop_scope (); + file_scope = 0; + + maybe_apply_pending_pragma_weaks (); +} + +/* Adjust the bindings for the start of a statement expression. */ + +void +c_bindings_start_stmt_expr (struct c_spot_bindings* switch_bindings) +{ + struct c_scope *scope; + + for (scope = current_scope; scope != NULL; scope = scope->outer) + { + struct c_binding *b; + + if (!scope->has_label_bindings) + continue; + + for (b = scope->bindings; b != NULL; b = b->prev) + { + struct c_label_vars *label_vars; + unsigned int ix; + struct c_goto_bindings *g; + + if (TREE_CODE (b->decl) != LABEL_DECL) + continue; + label_vars = b->u.label; + ++label_vars->label_bindings.stmt_exprs; + FOR_EACH_VEC_ELT (c_goto_bindings_p, label_vars->gotos, ix, g) + ++g->goto_bindings.stmt_exprs; + } + } + + if (switch_bindings != NULL) + ++switch_bindings->stmt_exprs; +} + +/* Adjust the bindings for the end of a statement expression. */ + +void +c_bindings_end_stmt_expr (struct c_spot_bindings *switch_bindings) +{ + struct c_scope *scope; + + for (scope = current_scope; scope != NULL; scope = scope->outer) + { + struct c_binding *b; + + if (!scope->has_label_bindings) + continue; + + for (b = scope->bindings; b != NULL; b = b->prev) + { + struct c_label_vars *label_vars; + unsigned int ix; + struct c_goto_bindings *g; + + if (TREE_CODE (b->decl) != LABEL_DECL) + continue; + label_vars = b->u.label; + --label_vars->label_bindings.stmt_exprs; + if (label_vars->label_bindings.stmt_exprs < 0) + { + label_vars->label_bindings.left_stmt_expr = true; + label_vars->label_bindings.stmt_exprs = 0; + } + FOR_EACH_VEC_ELT (c_goto_bindings_p, label_vars->gotos, ix, g) + { + --g->goto_bindings.stmt_exprs; + if (g->goto_bindings.stmt_exprs < 0) + { + g->goto_bindings.left_stmt_expr = true; + g->goto_bindings.stmt_exprs = 0; + } + } + } + } + + if (switch_bindings != NULL) + { + --switch_bindings->stmt_exprs; + gcc_assert (switch_bindings->stmt_exprs >= 0); + } +} + +/* 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, and has a location + of LOC. + + Note that the definition may really be just a forward reference. + In that case, the TYPE_SIZE will be zero. */ + +static void +pushtag (location_t loc, tree name, tree type) +{ + /* Record the identifier as the type's name if it has none. */ + if (name && !TYPE_NAME (type)) + TYPE_NAME (type) = name; + bind (name, type, current_scope, /*invisible=*/false, /*nested=*/false, loc); + + /* Create a fake NULL-named TYPE_DECL node whose TREE_TYPE will be the + tagged type we just added to the current scope. 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 (loc, + TYPE_DECL, NULL_TREE, type)); + + /* An approximation for now, so we can tell this is a function-scope tag. + This will be updated in pop_scope. */ + TYPE_CONTEXT (type) = DECL_CONTEXT (TYPE_STUB_DECL (type)); + + if (warn_cxx_compat && name != NULL_TREE) + { + struct c_binding *b = I_SYMBOL_BINDING (name); + + if (b != NULL + && b->decl != NULL_TREE + && TREE_CODE (b->decl) == TYPE_DECL + && (B_IN_CURRENT_SCOPE (b) + || (current_scope == file_scope && B_IN_EXTERNAL_SCOPE (b))) + && (TYPE_MAIN_VARIANT (TREE_TYPE (b->decl)) + != TYPE_MAIN_VARIANT (type))) + { + warning_at (loc, OPT_Wc___compat, + ("using %qD as both a typedef and a tag is " + "invalid in C++"), + b->decl); + if (b->locus != UNKNOWN_LOCATION) + inform (b->locus, "originally defined here"); + } + } +} + +/* Subroutine of compare_decls. Allow harmless mismatches in return + and argument types provided that the type modes match. This function + return a unified type given a suitable match, and 0 otherwise. */ + +static tree +match_builtin_function_types (tree newtype, tree oldtype) +{ + tree newrettype, oldrettype; + tree newargs, oldargs; + tree trytype, tryargs; + + /* Accept the return type of the new declaration if same modes. */ + oldrettype = TREE_TYPE (oldtype); + newrettype = TREE_TYPE (newtype); + + if (TYPE_MODE (oldrettype) != TYPE_MODE (newrettype)) + return 0; + + oldargs = TYPE_ARG_TYPES (oldtype); + newargs = TYPE_ARG_TYPES (newtype); + tryargs = newargs; + + while (oldargs || newargs) + { + if (!oldargs + || !newargs + || !TREE_VALUE (oldargs) + || !TREE_VALUE (newargs) + || TYPE_MODE (TREE_VALUE (oldargs)) + != TYPE_MODE (TREE_VALUE (newargs))) + return 0; + + oldargs = TREE_CHAIN (oldargs); + newargs = TREE_CHAIN (newargs); + } + + trytype = build_function_type (newrettype, tryargs); + return build_type_attribute_variant (trytype, TYPE_ATTRIBUTES (oldtype)); +} + +/* Subroutine of diagnose_mismatched_decls. Check for function type + mismatch involving an empty arglist vs a nonempty one and give clearer + diagnostics. */ +static void +diagnose_arglist_conflict (tree newdecl, tree olddecl, + tree newtype, tree oldtype) +{ + tree t; + + if (TREE_CODE (olddecl) != FUNCTION_DECL + || !comptypes (TREE_TYPE (oldtype), TREE_TYPE (newtype)) + || !((!prototype_p (oldtype) && DECL_INITIAL (olddecl) == 0) + || (!prototype_p (newtype) && DECL_INITIAL (newdecl) == 0))) + return; + + t = TYPE_ARG_TYPES (oldtype); + if (t == 0) + t = TYPE_ARG_TYPES (newtype); + for (; t; t = TREE_CHAIN (t)) + { + tree type = TREE_VALUE (t); + + if (TREE_CHAIN (t) == 0 + && TYPE_MAIN_VARIANT (type) != void_type_node) + { + inform (input_location, "a parameter list with an ellipsis can%'t match " + "an empty parameter name list declaration"); + break; + } + + if (c_type_promotes_to (type) != type) + { + inform (input_location, "an argument type that has a default promotion can%'t match " + "an empty parameter name list declaration"); + break; + } + } +} + +/* Another subroutine of diagnose_mismatched_decls. OLDDECL is an + old-style function definition, NEWDECL is a prototype declaration. + Diagnose inconsistencies in the argument list. Returns TRUE if + the prototype is compatible, FALSE if not. */ +static bool +validate_proto_after_old_defn (tree newdecl, tree newtype, tree oldtype) +{ + tree newargs, oldargs; + int i; + +#define END_OF_ARGLIST(t) ((t) == void_type_node) + + oldargs = TYPE_ACTUAL_ARG_TYPES (oldtype); + newargs = TYPE_ARG_TYPES (newtype); + i = 1; + + for (;;) + { + tree oldargtype = TREE_VALUE (oldargs); + tree newargtype = TREE_VALUE (newargs); + + if (oldargtype == error_mark_node || newargtype == error_mark_node) + return false; + + oldargtype = TYPE_MAIN_VARIANT (oldargtype); + newargtype = TYPE_MAIN_VARIANT (newargtype); + + if (END_OF_ARGLIST (oldargtype) && END_OF_ARGLIST (newargtype)) + break; + + /* Reaching the end of just one list means the two decls don't + agree on the number of arguments. */ + if (END_OF_ARGLIST (oldargtype)) + { + error ("prototype for %q+D declares more arguments " + "than previous old-style definition", newdecl); + return false; + } + else if (END_OF_ARGLIST (newargtype)) + { + error ("prototype for %q+D declares fewer arguments " + "than previous old-style definition", newdecl); + return false; + } + + /* Type for passing arg must be consistent with that declared + for the arg. */ + else if (!comptypes (oldargtype, newargtype)) + { + error ("prototype for %q+D declares argument %d" + " with incompatible type", + newdecl, i); + return false; + } + + oldargs = TREE_CHAIN (oldargs); + newargs = TREE_CHAIN (newargs); + i++; + } + + /* If we get here, no errors were found, but do issue a warning + for this poor-style construct. */ + warning (0, "prototype for %q+D follows non-prototype definition", + newdecl); + return true; +#undef END_OF_ARGLIST +} + +/* Subroutine of diagnose_mismatched_decls. Report the location of DECL, + first in a pair of mismatched declarations, using the diagnostic + function DIAG. */ +static void +locate_old_decl (tree decl) +{ + if (TREE_CODE (decl) == FUNCTION_DECL && DECL_BUILT_IN (decl)) + ; + else if (DECL_INITIAL (decl)) + inform (input_location, "previous definition of %q+D was here", decl); + else if (C_DECL_IMPLICIT (decl)) + inform (input_location, "previous implicit declaration of %q+D was here", decl); + else + inform (input_location, "previous declaration of %q+D was here", decl); +} + +/* Subroutine of duplicate_decls. Compare NEWDECL to OLDDECL. + Returns true if the caller should proceed to merge the two, false + if OLDDECL should simply be discarded. As a side effect, issues + all necessary diagnostics for invalid or poor-style combinations. + If it returns true, writes the types of NEWDECL and OLDDECL to + *NEWTYPEP and *OLDTYPEP - these may have been adjusted from + TREE_TYPE (NEWDECL, OLDDECL) respectively. */ + +static bool +diagnose_mismatched_decls (tree newdecl, tree olddecl, + tree *newtypep, tree *oldtypep) +{ + tree newtype, oldtype; + bool pedwarned = false; + bool warned = false; + bool retval = true; + +#define DECL_EXTERN_INLINE(DECL) (DECL_DECLARED_INLINE_P (DECL) \ + && DECL_EXTERNAL (DECL)) + + /* If we have error_mark_node for either decl or type, just discard + the previous decl - we're in an error cascade already. */ + if (olddecl == error_mark_node || newdecl == error_mark_node) + return false; + *oldtypep = oldtype = TREE_TYPE (olddecl); + *newtypep = newtype = TREE_TYPE (newdecl); + if (oldtype == error_mark_node || newtype == error_mark_node) + return false; + + /* Two different categories of symbol altogether. This is an error + unless OLDDECL is a builtin. OLDDECL will be discarded in any case. */ + if (TREE_CODE (olddecl) != TREE_CODE (newdecl)) + { + if (!(TREE_CODE (olddecl) == FUNCTION_DECL + && DECL_BUILT_IN (olddecl) + && !C_DECL_DECLARED_BUILTIN (olddecl))) + { + error ("%q+D redeclared as different kind of symbol", newdecl); + locate_old_decl (olddecl); + } + else if (TREE_PUBLIC (newdecl)) + warning (0, "built-in function %q+D declared as non-function", + newdecl); + else + warning (OPT_Wshadow, "declaration of %q+D shadows " + "a built-in function", newdecl); + return false; + } + + /* Enumerators have no linkage, so may only be declared once in a + given scope. */ + if (TREE_CODE (olddecl) == CONST_DECL) + { + error ("redeclaration of enumerator %q+D", newdecl); + locate_old_decl (olddecl); + return false; + } + + if (!comptypes (oldtype, newtype)) + { + if (TREE_CODE (olddecl) == FUNCTION_DECL + && DECL_BUILT_IN (olddecl) && !C_DECL_DECLARED_BUILTIN (olddecl)) + { + /* Accept harmless mismatch in function types. + This is for the ffs and fprintf builtins. */ + tree trytype = match_builtin_function_types (newtype, oldtype); + + if (trytype && comptypes (newtype, trytype)) + *oldtypep = oldtype = trytype; + else + { + /* If types don't match for a built-in, throw away the + built-in. No point in calling locate_old_decl here, it + won't print anything. */ + warning (0, "conflicting types for built-in function %q+D", + newdecl); + return false; + } + } + else if (TREE_CODE (olddecl) == FUNCTION_DECL + && DECL_IS_BUILTIN (olddecl)) + { + /* A conflicting function declaration for a predeclared + function that isn't actually built in. Objective C uses + these. The new declaration silently overrides everything + but the volatility (i.e. noreturn) indication. See also + below. FIXME: Make Objective C use normal builtins. */ + TREE_THIS_VOLATILE (newdecl) |= TREE_THIS_VOLATILE (olddecl); + return false; + } + /* Permit void foo (...) to match int foo (...) if the latter is + the definition and implicit int was used. See + c-torture/compile/920625-2.c. */ + else if (TREE_CODE (newdecl) == FUNCTION_DECL && DECL_INITIAL (newdecl) + && TYPE_MAIN_VARIANT (TREE_TYPE (oldtype)) == void_type_node + && TYPE_MAIN_VARIANT (TREE_TYPE (newtype)) == integer_type_node + && C_FUNCTION_IMPLICIT_INT (newdecl) && !DECL_INITIAL (olddecl)) + { + pedwarned = pedwarn (input_location, 0, + "conflicting types for %q+D", newdecl); + /* Make sure we keep void as the return type. */ + TREE_TYPE (newdecl) = *newtypep = newtype = oldtype; + C_FUNCTION_IMPLICIT_INT (newdecl) = 0; + } + /* Permit void foo (...) to match an earlier call to foo (...) with + no declared type (thus, implicitly int). */ + else if (TREE_CODE (newdecl) == FUNCTION_DECL + && TYPE_MAIN_VARIANT (TREE_TYPE (newtype)) == void_type_node + && TYPE_MAIN_VARIANT (TREE_TYPE (oldtype)) == integer_type_node + && C_DECL_IMPLICIT (olddecl) && !DECL_INITIAL (olddecl)) + { + pedwarned = pedwarn (input_location, 0, + "conflicting types for %q+D", newdecl); + /* Make sure we keep void as the return type. */ + TREE_TYPE (olddecl) = *oldtypep = oldtype = newtype; + } + else + { + int new_quals = TYPE_QUALS (newtype); + int old_quals = TYPE_QUALS (oldtype); + + if (new_quals != old_quals) + { + addr_space_t new_addr = DECODE_QUAL_ADDR_SPACE (new_quals); + addr_space_t old_addr = DECODE_QUAL_ADDR_SPACE (old_quals); + if (new_addr != old_addr) + { + if (ADDR_SPACE_GENERIC_P (new_addr)) + error ("conflicting named address spaces (generic vs %s) " + "for %q+D", + c_addr_space_name (old_addr), newdecl); + else if (ADDR_SPACE_GENERIC_P (old_addr)) + error ("conflicting named address spaces (%s vs generic) " + "for %q+D", + c_addr_space_name (new_addr), newdecl); + else + error ("conflicting named address spaces (%s vs %s) " + "for %q+D", + c_addr_space_name (new_addr), + c_addr_space_name (old_addr), + newdecl); + } + + if (CLEAR_QUAL_ADDR_SPACE (new_quals) + != CLEAR_QUAL_ADDR_SPACE (old_quals)) + error ("conflicting type qualifiers for %q+D", newdecl); + } + else + error ("conflicting types for %q+D", newdecl); + diagnose_arglist_conflict (newdecl, olddecl, newtype, oldtype); + locate_old_decl (olddecl); + return false; + } + } + + /* Redeclaration of a type is a constraint violation (6.7.2.3p1), + but silently ignore the redeclaration if either is in a system + header. (Conflicting redeclarations were handled above.) This + is allowed for C11 if the types are the same, not just + compatible. */ + if (TREE_CODE (newdecl) == TYPE_DECL) + { + bool types_different = false; + int comptypes_result; + + comptypes_result + = comptypes_check_different_types (oldtype, newtype, &types_different); + + if (comptypes_result != 1 || types_different) + { + error ("redefinition of typedef %q+D with different type", newdecl); + locate_old_decl (olddecl); + return false; + } + + if (DECL_IN_SYSTEM_HEADER (newdecl) + || DECL_IN_SYSTEM_HEADER (olddecl) + || TREE_NO_WARNING (newdecl) + || TREE_NO_WARNING (olddecl)) + return true; /* Allow OLDDECL to continue in use. */ + + if (variably_modified_type_p (newtype, NULL)) + { + error ("redefinition of typedef %q+D with variably modified type", + newdecl); + locate_old_decl (olddecl); + } + else if (pedantic && !flag_isoc11) + { + pedwarn (input_location, OPT_Wpedantic, + "redefinition of typedef %q+D", newdecl); + locate_old_decl (olddecl); + } + + return true; + } + + /* Function declarations can either be 'static' or 'extern' (no + qualifier is equivalent to 'extern' - C99 6.2.2p5) and therefore + can never conflict with each other on account of linkage + (6.2.2p4). Multiple definitions are not allowed (6.9p3,5) but + gnu89 mode permits two definitions if one is 'extern inline' and + one is not. The non- extern-inline definition supersedes the + extern-inline definition. */ + + else if (TREE_CODE (newdecl) == FUNCTION_DECL) + { + /* If you declare a built-in function name as static, or + define the built-in with an old-style definition (so we + can't validate the argument list) the built-in definition is + overridden, but optionally warn this was a bad choice of name. */ + if (DECL_BUILT_IN (olddecl) + && !C_DECL_DECLARED_BUILTIN (olddecl) + && (!TREE_PUBLIC (newdecl) + || (DECL_INITIAL (newdecl) + && !prototype_p (TREE_TYPE (newdecl))))) + { + warning (OPT_Wshadow, "declaration of %q+D shadows " + "a built-in function", newdecl); + /* Discard the old built-in function. */ + return false; + } + + if (DECL_INITIAL (newdecl)) + { + if (DECL_INITIAL (olddecl)) + { + /* If both decls are in the same TU and the new declaration + isn't overriding an extern inline reject the new decl. + In c99, no overriding is allowed in the same translation + unit. */ + if ((!DECL_EXTERN_INLINE (olddecl) + || DECL_EXTERN_INLINE (newdecl) + || (!flag_gnu89_inline + && (!DECL_DECLARED_INLINE_P (olddecl) + || !lookup_attribute ("gnu_inline", + DECL_ATTRIBUTES (olddecl))) + && (!DECL_DECLARED_INLINE_P (newdecl) + || !lookup_attribute ("gnu_inline", + DECL_ATTRIBUTES (newdecl)))) + ) + && same_translation_unit_p (newdecl, olddecl)) + { + error ("redefinition of %q+D", newdecl); + locate_old_decl (olddecl); + return false; + } + } + } + /* If we have a prototype after an old-style function definition, + the argument types must be checked specially. */ + else if (DECL_INITIAL (olddecl) + && !prototype_p (oldtype) && prototype_p (newtype) + && TYPE_ACTUAL_ARG_TYPES (oldtype) + && !validate_proto_after_old_defn (newdecl, newtype, oldtype)) + { + locate_old_decl (olddecl); + return false; + } + /* A non-static declaration (even an "extern") followed by a + static declaration is undefined behavior per C99 6.2.2p3-5,7. + The same is true for a static forward declaration at block + scope followed by a non-static declaration/definition at file + scope. Static followed by non-static at the same scope is + not undefined behavior, and is the most convenient way to get + some effects (see e.g. what unwind-dw2-fde-glibc.c does to + the definition of _Unwind_Find_FDE in unwind-dw2-fde.c), but + we do diagnose it if -Wtraditional. */ + if (TREE_PUBLIC (olddecl) && !TREE_PUBLIC (newdecl)) + { + /* Two exceptions to the rule. If olddecl is an extern + inline, or a predeclared function that isn't actually + built in, newdecl silently overrides olddecl. The latter + occur only in Objective C; see also above. (FIXME: Make + Objective C use normal builtins.) */ + if (!DECL_IS_BUILTIN (olddecl) + && !DECL_EXTERN_INLINE (olddecl)) + { + error ("static declaration of %q+D follows " + "non-static declaration", newdecl); + locate_old_decl (olddecl); + } + return false; + } + else if (TREE_PUBLIC (newdecl) && !TREE_PUBLIC (olddecl)) + { + if (DECL_CONTEXT (olddecl)) + { + error ("non-static declaration of %q+D follows " + "static declaration", newdecl); + locate_old_decl (olddecl); + return false; + } + else if (warn_traditional) + { + warned |= warning (OPT_Wtraditional, + "non-static declaration of %q+D " + "follows static declaration", newdecl); + } + } + + /* Make sure gnu_inline attribute is either not present, or + present on all inline decls. */ + if (DECL_DECLARED_INLINE_P (olddecl) + && DECL_DECLARED_INLINE_P (newdecl)) + { + bool newa = lookup_attribute ("gnu_inline", + DECL_ATTRIBUTES (newdecl)) != NULL; + bool olda = lookup_attribute ("gnu_inline", + DECL_ATTRIBUTES (olddecl)) != NULL; + if (newa != olda) + { + error_at (input_location, "%<gnu_inline%> attribute present on %q+D", + newa ? newdecl : olddecl); + error_at (DECL_SOURCE_LOCATION (newa ? olddecl : newdecl), + "but not here"); + } + } + } + else if (TREE_CODE (newdecl) == VAR_DECL) + { + /* Only variables can be thread-local, and all declarations must + agree on this property. */ + if (C_DECL_THREADPRIVATE_P (olddecl) && !DECL_THREAD_LOCAL_P (newdecl)) + { + /* Nothing to check. Since OLDDECL is marked threadprivate + and NEWDECL does not have a thread-local attribute, we + will merge the threadprivate attribute into NEWDECL. */ + ; + } + else if (DECL_THREAD_LOCAL_P (newdecl) != DECL_THREAD_LOCAL_P (olddecl)) + { + if (DECL_THREAD_LOCAL_P (newdecl)) + error ("thread-local declaration of %q+D follows " + "non-thread-local declaration", newdecl); + else + error ("non-thread-local declaration of %q+D follows " + "thread-local declaration", newdecl); + + locate_old_decl (olddecl); + return false; + } + + /* Multiple initialized definitions are not allowed (6.9p3,5). */ + if (DECL_INITIAL (newdecl) && DECL_INITIAL (olddecl)) + { + error ("redefinition of %q+D", newdecl); + locate_old_decl (olddecl); + return false; + } + + /* Objects declared at file scope: if the first declaration had + external linkage (even if it was an external reference) the + second must have external linkage as well, or the behavior is + undefined. If the first declaration had internal linkage, then + the second must too, or else be an external reference (in which + case the composite declaration still has internal linkage). + As for function declarations, we warn about the static-then- + extern case only for -Wtraditional. See generally 6.2.2p3-5,7. */ + if (DECL_FILE_SCOPE_P (newdecl) + && TREE_PUBLIC (newdecl) != TREE_PUBLIC (olddecl)) + { + if (DECL_EXTERNAL (newdecl)) + { + if (!DECL_FILE_SCOPE_P (olddecl)) + { + error ("extern declaration of %q+D follows " + "declaration with no linkage", newdecl); + locate_old_decl (olddecl); + return false; + } + else if (warn_traditional) + { + warned |= warning (OPT_Wtraditional, + "non-static declaration of %q+D " + "follows static declaration", newdecl); + } + } + else + { + if (TREE_PUBLIC (newdecl)) + error ("non-static declaration of %q+D follows " + "static declaration", newdecl); + else + error ("static declaration of %q+D follows " + "non-static declaration", newdecl); + + locate_old_decl (olddecl); + return false; + } + } + /* Two objects with the same name declared at the same block + scope must both be external references (6.7p3). */ + else if (!DECL_FILE_SCOPE_P (newdecl)) + { + if (DECL_EXTERNAL (newdecl)) + { + /* Extern with initializer at block scope, which will + already have received an error. */ + } + else if (DECL_EXTERNAL (olddecl)) + { + error ("declaration of %q+D with no linkage follows " + "extern declaration", newdecl); + locate_old_decl (olddecl); + } + else + { + error ("redeclaration of %q+D with no linkage", newdecl); + locate_old_decl (olddecl); + } + + return false; + } + + /* C++ does not permit a decl to appear multiple times at file + scope. */ + if (warn_cxx_compat + && DECL_FILE_SCOPE_P (newdecl) + && !DECL_EXTERNAL (newdecl) + && !DECL_EXTERNAL (olddecl)) + warned |= warning_at (DECL_SOURCE_LOCATION (newdecl), + OPT_Wc___compat, + ("duplicate declaration of %qD is " + "invalid in C++"), + newdecl); + } + + /* warnings */ + /* All decls must agree on a visibility. */ + if (CODE_CONTAINS_STRUCT (TREE_CODE (newdecl), TS_DECL_WITH_VIS) + && DECL_VISIBILITY_SPECIFIED (newdecl) && DECL_VISIBILITY_SPECIFIED (olddecl) + && DECL_VISIBILITY (newdecl) != DECL_VISIBILITY (olddecl)) + { + warned |= warning (0, "redeclaration of %q+D with different visibility " + "(old visibility preserved)", newdecl); + } + + if (TREE_CODE (newdecl) == FUNCTION_DECL) + { + /* Diagnose inline __attribute__ ((noinline)) which is silly. */ + if (DECL_DECLARED_INLINE_P (newdecl) + && lookup_attribute ("noinline", DECL_ATTRIBUTES (olddecl))) + { + warned |= warning (OPT_Wattributes, + "inline declaration of %qD follows " + "declaration with attribute noinline", newdecl); + } + else if (DECL_DECLARED_INLINE_P (olddecl) + && lookup_attribute ("noinline", DECL_ATTRIBUTES (newdecl))) + { + warned |= warning (OPT_Wattributes, + "declaration of %q+D with attribute " + "noinline follows inline declaration ", newdecl); + } + } + else /* PARM_DECL, VAR_DECL */ + { + /* Redeclaration of a parameter is a constraint violation (this is + not explicitly stated, but follows from C99 6.7p3 [no more than + one declaration of the same identifier with no linkage in the + same scope, except type tags] and 6.2.2p6 [parameters have no + linkage]). We must check for a forward parameter declaration, + indicated by TREE_ASM_WRITTEN on the old declaration - this is + an extension, the mandatory diagnostic for which is handled by + mark_forward_parm_decls. */ + + if (TREE_CODE (newdecl) == PARM_DECL + && (!TREE_ASM_WRITTEN (olddecl) || TREE_ASM_WRITTEN (newdecl))) + { + error ("redefinition of parameter %q+D", newdecl); + locate_old_decl (olddecl); + return false; + } + } + + /* Optional warning for completely redundant decls. */ + if (!warned && !pedwarned + && warn_redundant_decls + /* Don't warn about a function declaration followed by a + definition. */ + && !(TREE_CODE (newdecl) == FUNCTION_DECL + && DECL_INITIAL (newdecl) && !DECL_INITIAL (olddecl)) + /* Don't warn about redundant redeclarations of builtins. */ + && !(TREE_CODE (newdecl) == FUNCTION_DECL + && !DECL_BUILT_IN (newdecl) + && DECL_BUILT_IN (olddecl) + && !C_DECL_DECLARED_BUILTIN (olddecl)) + /* Don't warn about an extern followed by a definition. */ + && !(DECL_EXTERNAL (olddecl) && !DECL_EXTERNAL (newdecl)) + /* Don't warn about forward parameter decls. */ + && !(TREE_CODE (newdecl) == PARM_DECL + && TREE_ASM_WRITTEN (olddecl) && !TREE_ASM_WRITTEN (newdecl)) + /* Don't warn about a variable definition following a declaration. */ + && !(TREE_CODE (newdecl) == VAR_DECL + && DECL_INITIAL (newdecl) && !DECL_INITIAL (olddecl))) + { + warned = warning (OPT_Wredundant_decls, "redundant redeclaration of %q+D", + newdecl); + } + + /* Report location of previous decl/defn. */ + if (warned || pedwarned) + locate_old_decl (olddecl); + +#undef DECL_EXTERN_INLINE + + return retval; +} + +/* Subroutine of duplicate_decls. NEWDECL has been found to be + consistent with OLDDECL, but carries new information. Merge the + new information into OLDDECL. This function issues no + diagnostics. */ + +static void +merge_decls (tree newdecl, tree olddecl, tree newtype, tree oldtype) +{ + bool new_is_definition = (TREE_CODE (newdecl) == FUNCTION_DECL + && DECL_INITIAL (newdecl) != 0); + bool new_is_prototype = (TREE_CODE (newdecl) == FUNCTION_DECL + && prototype_p (TREE_TYPE (newdecl))); + bool old_is_prototype = (TREE_CODE (olddecl) == FUNCTION_DECL + && prototype_p (TREE_TYPE (olddecl))); + + /* For real parm decl following a forward decl, rechain the old decl + in its new location and clear TREE_ASM_WRITTEN (it's not a + forward decl anymore). */ + if (TREE_CODE (newdecl) == PARM_DECL + && TREE_ASM_WRITTEN (olddecl) && !TREE_ASM_WRITTEN (newdecl)) + { + struct c_binding *b, **here; + + for (here = ¤t_scope->bindings; *here; here = &(*here)->prev) + if ((*here)->decl == olddecl) + goto found; + gcc_unreachable (); + + found: + b = *here; + *here = b->prev; + b->prev = current_scope->bindings; + current_scope->bindings = b; + + TREE_ASM_WRITTEN (olddecl) = 0; + } + + DECL_ATTRIBUTES (newdecl) + = targetm.merge_decl_attributes (olddecl, newdecl); + + /* Merge the data types specified in the two decls. */ + TREE_TYPE (newdecl) + = TREE_TYPE (olddecl) + = composite_type (newtype, oldtype); + + /* Lay the type out, unless already done. */ + if (!comptypes (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); + DECL_SIZE_UNIT (newdecl) = DECL_SIZE_UNIT (olddecl); + DECL_MODE (newdecl) = DECL_MODE (olddecl); + if (DECL_ALIGN (olddecl) > DECL_ALIGN (newdecl)) + { + DECL_ALIGN (newdecl) = DECL_ALIGN (olddecl); + DECL_USER_ALIGN (newdecl) |= DECL_USER_ALIGN (olddecl); + } + } + + /* Keep the old rtl since we can safely use it. */ + if (HAS_RTL_P (olddecl)) + COPY_DECL_RTL (olddecl, newdecl); + + /* Merge the type qualifiers. */ + if (TREE_READONLY (newdecl)) + TREE_READONLY (olddecl) = 1; + + if (TREE_THIS_VOLATILE (newdecl)) + TREE_THIS_VOLATILE (olddecl) = 1; + + /* Merge deprecatedness. */ + if (TREE_DEPRECATED (newdecl)) + TREE_DEPRECATED (olddecl) = 1; + + /* If a decl is in a system header and the other isn't, keep the one on the + system header. Otherwise, keep source location of definition rather than + declaration and of prototype rather than non-prototype unless that + prototype is built-in. */ + if (CODE_CONTAINS_STRUCT (TREE_CODE (olddecl), TS_DECL_WITH_VIS) + && DECL_IN_SYSTEM_HEADER (olddecl) + && !DECL_IN_SYSTEM_HEADER (newdecl) ) + DECL_SOURCE_LOCATION (newdecl) = DECL_SOURCE_LOCATION (olddecl); + else if (CODE_CONTAINS_STRUCT (TREE_CODE (olddecl), TS_DECL_WITH_VIS) + && DECL_IN_SYSTEM_HEADER (newdecl) + && !DECL_IN_SYSTEM_HEADER (olddecl)) + DECL_SOURCE_LOCATION (olddecl) = DECL_SOURCE_LOCATION (newdecl); + else if ((DECL_INITIAL (newdecl) == 0 && DECL_INITIAL (olddecl) != 0) + || (old_is_prototype && !new_is_prototype + && !C_DECL_BUILTIN_PROTOTYPE (olddecl))) + DECL_SOURCE_LOCATION (newdecl) = DECL_SOURCE_LOCATION (olddecl); + + /* Merge the initialization information. */ + if (DECL_INITIAL (newdecl) == 0) + DECL_INITIAL (newdecl) = DECL_INITIAL (olddecl); + + /* Merge the threadprivate attribute. */ + if (TREE_CODE (olddecl) == VAR_DECL && C_DECL_THREADPRIVATE_P (olddecl)) + { + DECL_TLS_MODEL (newdecl) = DECL_TLS_MODEL (olddecl); + C_DECL_THREADPRIVATE_P (newdecl) = 1; + } + + if (CODE_CONTAINS_STRUCT (TREE_CODE (olddecl), TS_DECL_WITH_VIS)) + { + /* 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); + + /* Copy the assembler name. + Currently, it can only be defined in the prototype. */ + COPY_DECL_ASSEMBLER_NAME (olddecl, newdecl); + + /* Use visibility of whichever declaration had it specified */ + if (DECL_VISIBILITY_SPECIFIED (olddecl)) + { + DECL_VISIBILITY (newdecl) = DECL_VISIBILITY (olddecl); + DECL_VISIBILITY_SPECIFIED (newdecl) = 1; + } + + if (TREE_CODE (newdecl) == FUNCTION_DECL) + { + DECL_STATIC_CONSTRUCTOR(newdecl) |= DECL_STATIC_CONSTRUCTOR(olddecl); + DECL_STATIC_DESTRUCTOR (newdecl) |= DECL_STATIC_DESTRUCTOR (olddecl); + DECL_NO_LIMIT_STACK (newdecl) |= DECL_NO_LIMIT_STACK (olddecl); + DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (newdecl) + |= DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (olddecl); + TREE_THIS_VOLATILE (newdecl) |= TREE_THIS_VOLATILE (olddecl); + DECL_IS_MALLOC (newdecl) |= DECL_IS_MALLOC (olddecl); + DECL_IS_OPERATOR_NEW (newdecl) |= DECL_IS_OPERATOR_NEW (olddecl); + TREE_READONLY (newdecl) |= TREE_READONLY (olddecl); + DECL_PURE_P (newdecl) |= DECL_PURE_P (olddecl); + DECL_IS_NOVOPS (newdecl) |= DECL_IS_NOVOPS (olddecl); + } + + /* Merge the storage class information. */ + merge_weak (newdecl, 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. */ + 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; + } + } + + /* In c99, 'extern' declaration before (or after) 'inline' means this + function is not DECL_EXTERNAL, unless 'gnu_inline' attribute + is present. */ + if (TREE_CODE (newdecl) == FUNCTION_DECL + && !flag_gnu89_inline + && (DECL_DECLARED_INLINE_P (newdecl) + || DECL_DECLARED_INLINE_P (olddecl)) + && (!DECL_DECLARED_INLINE_P (newdecl) + || !DECL_DECLARED_INLINE_P (olddecl) + || !DECL_EXTERNAL (olddecl)) + && DECL_EXTERNAL (newdecl) + && !lookup_attribute ("gnu_inline", DECL_ATTRIBUTES (newdecl)) + && !current_function_decl) + DECL_EXTERNAL (newdecl) = 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); + DECL_COMMON (newdecl) = DECL_COMMON (olddecl); + } + } + else + { + TREE_STATIC (olddecl) = TREE_STATIC (newdecl); + TREE_PUBLIC (olddecl) = TREE_PUBLIC (newdecl); + } + + if (TREE_CODE (newdecl) == FUNCTION_DECL) + { + /* If we're redefining a function previously defined as extern + inline, make sure we emit debug info for the inline before we + throw it away, in case it was inlined into a function that + hasn't been written out yet. */ + if (new_is_definition && DECL_INITIAL (olddecl)) + /* The new defn must not be inline. */ + DECL_UNINLINABLE (newdecl) = 1; + else + { + /* If either decl says `inline', this fn is inline, unless + its definition was passed already. */ + if (DECL_DECLARED_INLINE_P (newdecl) + || DECL_DECLARED_INLINE_P (olddecl)) + DECL_DECLARED_INLINE_P (newdecl) = 1; + + DECL_UNINLINABLE (newdecl) = DECL_UNINLINABLE (olddecl) + = (DECL_UNINLINABLE (newdecl) || DECL_UNINLINABLE (olddecl)); + + DECL_DISREGARD_INLINE_LIMITS (newdecl) + = DECL_DISREGARD_INLINE_LIMITS (olddecl) + = (DECL_DISREGARD_INLINE_LIMITS (newdecl) + || DECL_DISREGARD_INLINE_LIMITS (olddecl)); + } + + if (DECL_BUILT_IN (olddecl)) + { + /* If redeclaring a builtin function, it stays built in. + But it gets tagged as having been declared. */ + DECL_BUILT_IN_CLASS (newdecl) = DECL_BUILT_IN_CLASS (olddecl); + DECL_FUNCTION_CODE (newdecl) = DECL_FUNCTION_CODE (olddecl); + C_DECL_DECLARED_BUILTIN (newdecl) = 1; + if (new_is_prototype) + { + C_DECL_BUILTIN_PROTOTYPE (newdecl) = 0; + if (DECL_BUILT_IN_CLASS (newdecl) == BUILT_IN_NORMAL) + { + enum built_in_function fncode = DECL_FUNCTION_CODE (newdecl); + switch (fncode) + { + /* If a compatible prototype of these builtin functions + is seen, assume the runtime implements it with the + expected semantics. */ + case BUILT_IN_STPCPY: + if (builtin_decl_explicit_p (fncode)) + set_builtin_decl_implicit_p (fncode, true); + break; + default: + break; + } + } + } + else + C_DECL_BUILTIN_PROTOTYPE (newdecl) + = C_DECL_BUILTIN_PROTOTYPE (olddecl); + } + + /* Preserve function specific target and optimization options */ + if (DECL_FUNCTION_SPECIFIC_TARGET (olddecl) + && !DECL_FUNCTION_SPECIFIC_TARGET (newdecl)) + DECL_FUNCTION_SPECIFIC_TARGET (newdecl) + = DECL_FUNCTION_SPECIFIC_TARGET (olddecl); + + if (DECL_FUNCTION_SPECIFIC_OPTIMIZATION (olddecl) + && !DECL_FUNCTION_SPECIFIC_OPTIMIZATION (newdecl)) + DECL_FUNCTION_SPECIFIC_OPTIMIZATION (newdecl) + = DECL_FUNCTION_SPECIFIC_OPTIMIZATION (olddecl); + + /* Also preserve various other info from the definition. */ + if (!new_is_definition) + { + tree t; + DECL_RESULT (newdecl) = DECL_RESULT (olddecl); + DECL_INITIAL (newdecl) = DECL_INITIAL (olddecl); + DECL_STRUCT_FUNCTION (newdecl) = DECL_STRUCT_FUNCTION (olddecl); + DECL_SAVED_TREE (newdecl) = DECL_SAVED_TREE (olddecl); + DECL_ARGUMENTS (newdecl) = copy_list (DECL_ARGUMENTS (olddecl)); + for (t = DECL_ARGUMENTS (newdecl); t ; t = DECL_CHAIN (t)) + DECL_CONTEXT (t) = newdecl; + + /* See if we've got a function to instantiate from. */ + if (DECL_SAVED_TREE (olddecl)) + DECL_ABSTRACT_ORIGIN (newdecl) + = DECL_ABSTRACT_ORIGIN (olddecl); + } + } + + /* Merge the USED information. */ + if (TREE_USED (olddecl)) + TREE_USED (newdecl) = 1; + else if (TREE_USED (newdecl)) + TREE_USED (olddecl) = 1; + if (TREE_CODE (olddecl) == VAR_DECL || TREE_CODE (olddecl) == PARM_DECL) + DECL_READ_P (newdecl) |= DECL_READ_P (olddecl); + if (DECL_PRESERVE_P (olddecl)) + DECL_PRESERVE_P (newdecl) = 1; + else if (DECL_PRESERVE_P (newdecl)) + DECL_PRESERVE_P (olddecl) = 1; + + /* Copy most of the decl-specific fields of NEWDECL into OLDDECL. + But preserve OLDDECL's DECL_UID, DECL_CONTEXT and + DECL_ARGUMENTS (if appropriate). */ + { + unsigned olddecl_uid = DECL_UID (olddecl); + tree olddecl_context = DECL_CONTEXT (olddecl); + tree olddecl_arguments = NULL; + if (TREE_CODE (olddecl) == FUNCTION_DECL) + olddecl_arguments = DECL_ARGUMENTS (olddecl); + + memcpy ((char *) olddecl + sizeof (struct tree_common), + (char *) newdecl + sizeof (struct tree_common), + sizeof (struct tree_decl_common) - sizeof (struct tree_common)); + DECL_USER_ALIGN (olddecl) = DECL_USER_ALIGN (newdecl); + switch (TREE_CODE (olddecl)) + { + case FUNCTION_DECL: + case FIELD_DECL: + case VAR_DECL: + case PARM_DECL: + case LABEL_DECL: + case RESULT_DECL: + case CONST_DECL: + case TYPE_DECL: + memcpy ((char *) olddecl + sizeof (struct tree_decl_common), + (char *) newdecl + sizeof (struct tree_decl_common), + tree_code_size (TREE_CODE (olddecl)) - sizeof (struct tree_decl_common)); + break; + + default: + + memcpy ((char *) olddecl + sizeof (struct tree_decl_common), + (char *) newdecl + sizeof (struct tree_decl_common), + sizeof (struct tree_decl_non_common) - sizeof (struct tree_decl_common)); + } + DECL_UID (olddecl) = olddecl_uid; + DECL_CONTEXT (olddecl) = olddecl_context; + if (TREE_CODE (olddecl) == FUNCTION_DECL) + DECL_ARGUMENTS (olddecl) = olddecl_arguments; + } + + /* If OLDDECL had its DECL_RTL instantiated, re-invoke make_decl_rtl + so that encode_section_info has a chance to look at the new decl + flags and attributes. */ + if (DECL_RTL_SET_P (olddecl) + && (TREE_CODE (olddecl) == FUNCTION_DECL + || (TREE_CODE (olddecl) == VAR_DECL + && TREE_STATIC (olddecl)))) + make_decl_rtl (olddecl); +} + +/* 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 + true. Otherwise, return false. */ + +static bool +duplicate_decls (tree newdecl, tree olddecl) +{ + tree newtype = NULL, oldtype = NULL; + + if (!diagnose_mismatched_decls (newdecl, olddecl, &newtype, &oldtype)) + { + /* Avoid `unused variable' and other warnings for OLDDECL. */ + TREE_NO_WARNING (olddecl) = 1; + return false; + } + + merge_decls (newdecl, olddecl, newtype, oldtype); + return true; +} + + +/* Check whether decl-node NEW_DECL shadows an existing declaration. */ +static void +warn_if_shadowing (tree new_decl) +{ + struct c_binding *b; + + /* Shadow warnings wanted? */ + if (!warn_shadow + /* No shadow warnings for internally generated vars. */ + || DECL_IS_BUILTIN (new_decl) + /* No shadow warnings for vars made for inlining. */ + || DECL_FROM_INLINE (new_decl)) + return; + + /* Is anything being shadowed? Invisible decls do not count. */ + for (b = I_SYMBOL_BINDING (DECL_NAME (new_decl)); b; b = b->shadowed) + if (b->decl && b->decl != new_decl && !b->invisible + && (b->decl == error_mark_node + || diagnostic_report_warnings_p (global_dc, + DECL_SOURCE_LOCATION (b->decl)))) + { + tree old_decl = b->decl; + + if (old_decl == error_mark_node) + { + warning (OPT_Wshadow, "declaration of %q+D shadows previous " + "non-variable", new_decl); + break; + } + else if (TREE_CODE (old_decl) == PARM_DECL) + warning (OPT_Wshadow, "declaration of %q+D shadows a parameter", + new_decl); + else if (DECL_FILE_SCOPE_P (old_decl)) + warning (OPT_Wshadow, "declaration of %q+D shadows a global " + "declaration", new_decl); + else if (TREE_CODE (old_decl) == FUNCTION_DECL + && DECL_BUILT_IN (old_decl)) + { + warning (OPT_Wshadow, "declaration of %q+D shadows " + "a built-in function", new_decl); + break; + } + else + warning (OPT_Wshadow, "declaration of %q+D shadows a previous local", + new_decl); + + warning_at (DECL_SOURCE_LOCATION (old_decl), OPT_Wshadow, + "shadowed declaration is here"); + + break; + } +} + +/* 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. */ + +tree +pushdecl (tree x) +{ + tree name = DECL_NAME (x); + struct c_scope *scope = current_scope; + struct c_binding *b; + bool nested = false; + location_t locus = DECL_SOURCE_LOCATION (x); + + /* Must set DECL_CONTEXT for everything not at file scope or + DECL_FILE_SCOPE_P won't work. Local externs don't count + unless they have initializers (which generate code). */ + if (current_function_decl + && ((TREE_CODE (x) != FUNCTION_DECL && TREE_CODE (x) != VAR_DECL) + || DECL_INITIAL (x) || !DECL_EXTERNAL (x))) + DECL_CONTEXT (x) = current_function_decl; + + /* Anonymous decls are just inserted in the scope. */ + if (!name) + { + bind (name, x, scope, /*invisible=*/false, /*nested=*/false, + locus); + return x; + } + + /* First, see if there is another declaration with the same name in + the current scope. If there is, duplicate_decls may do all the + work for us. If duplicate_decls returns false, that indicates + two incompatible decls in the same scope; we are to silently + replace the old one (duplicate_decls has issued all appropriate + diagnostics). In particular, we should not consider possible + duplicates in the external scope, or shadowing. */ + b = I_SYMBOL_BINDING (name); + if (b && B_IN_SCOPE (b, scope)) + { + struct c_binding *b_ext, *b_use; + tree type = TREE_TYPE (x); + tree visdecl = b->decl; + tree vistype = TREE_TYPE (visdecl); + if (TREE_CODE (TREE_TYPE (x)) == ARRAY_TYPE + && COMPLETE_TYPE_P (TREE_TYPE (x))) + b->inner_comp = false; + b_use = b; + b_ext = b; + /* If this is an external linkage declaration, we should check + for compatibility with the type in the external scope before + setting the type at this scope based on the visible + information only. */ + if (TREE_PUBLIC (x) && TREE_PUBLIC (visdecl)) + { + while (b_ext && !B_IN_EXTERNAL_SCOPE (b_ext)) + b_ext = b_ext->shadowed; + if (b_ext) + { + b_use = b_ext; + if (b_use->u.type) + TREE_TYPE (b_use->decl) = b_use->u.type; + } + } + if (duplicate_decls (x, b_use->decl)) + { + if (b_use != b) + { + /* Save the updated type in the external scope and + restore the proper type for this scope. */ + tree thistype; + if (comptypes (vistype, type)) + thistype = composite_type (vistype, type); + else + thistype = TREE_TYPE (b_use->decl); + b_use->u.type = TREE_TYPE (b_use->decl); + if (TREE_CODE (b_use->decl) == FUNCTION_DECL + && DECL_BUILT_IN (b_use->decl)) + thistype + = build_type_attribute_variant (thistype, + TYPE_ATTRIBUTES + (b_use->u.type)); + TREE_TYPE (b_use->decl) = thistype; + } + return b_use->decl; + } + else + goto skip_external_and_shadow_checks; + } + + /* All declarations with external linkage, and all external + references, go in the external scope, no matter what scope is + current. However, the binding in that scope is ignored for + purposes of normal name lookup. A separate binding structure is + created in the requested scope; this governs the normal + visibility of the symbol. + + The binding in the externals scope is used exclusively for + detecting duplicate declarations of the same object, no matter + what scope they are in; this is what we do here. (C99 6.2.7p2: + All declarations that refer to the same object or function shall + have compatible type; otherwise, the behavior is undefined.) */ + if (DECL_EXTERNAL (x) || scope == file_scope) + { + tree type = TREE_TYPE (x); + tree vistype = 0; + tree visdecl = 0; + bool type_saved = false; + if (b && !B_IN_EXTERNAL_SCOPE (b) + && (TREE_CODE (b->decl) == FUNCTION_DECL + || TREE_CODE (b->decl) == VAR_DECL) + && DECL_FILE_SCOPE_P (b->decl)) + { + visdecl = b->decl; + vistype = TREE_TYPE (visdecl); + } + if (scope != file_scope + && !DECL_IN_SYSTEM_HEADER (x)) + warning (OPT_Wnested_externs, "nested extern declaration of %qD", x); + + while (b && !B_IN_EXTERNAL_SCOPE (b)) + { + /* If this decl might be modified, save its type. This is + done here rather than when the decl is first bound + because the type may change after first binding, through + being completed or through attributes being added. If we + encounter multiple such decls, only the first should have + its type saved; the others will already have had their + proper types saved and the types will not have changed as + their scopes will not have been re-entered. */ + if (DECL_P (b->decl) && DECL_FILE_SCOPE_P (b->decl) && !type_saved) + { + b->u.type = TREE_TYPE (b->decl); + type_saved = true; + } + if (B_IN_FILE_SCOPE (b) + && TREE_CODE (b->decl) == VAR_DECL + && TREE_STATIC (b->decl) + && TREE_CODE (TREE_TYPE (b->decl)) == ARRAY_TYPE + && !TYPE_DOMAIN (TREE_TYPE (b->decl)) + && TREE_CODE (type) == ARRAY_TYPE + && TYPE_DOMAIN (type) + && TYPE_MAX_VALUE (TYPE_DOMAIN (type)) + && !integer_zerop (TYPE_MAX_VALUE (TYPE_DOMAIN (type)))) + { + /* Array type completed in inner scope, which should be + diagnosed if the completion does not have size 1 and + it does not get completed in the file scope. */ + b->inner_comp = true; + } + b = b->shadowed; + } + + /* If a matching external declaration has been found, set its + type to the composite of all the types of that declaration. + After the consistency checks, it will be reset to the + composite of the visible types only. */ + if (b && (TREE_PUBLIC (x) || same_translation_unit_p (x, b->decl)) + && b->u.type) + TREE_TYPE (b->decl) = b->u.type; + + /* The point of the same_translation_unit_p check here is, + we want to detect a duplicate decl for a construct like + foo() { extern bar(); } ... static bar(); but not if + they are in different translation units. In any case, + the static does not go in the externals scope. */ + if (b + && (TREE_PUBLIC (x) || same_translation_unit_p (x, b->decl)) + && duplicate_decls (x, b->decl)) + { + tree thistype; + if (vistype) + { + if (comptypes (vistype, type)) + thistype = composite_type (vistype, type); + else + thistype = TREE_TYPE (b->decl); + } + else + thistype = type; + b->u.type = TREE_TYPE (b->decl); + if (TREE_CODE (b->decl) == FUNCTION_DECL && DECL_BUILT_IN (b->decl)) + thistype + = build_type_attribute_variant (thistype, + TYPE_ATTRIBUTES (b->u.type)); + TREE_TYPE (b->decl) = thistype; + bind (name, b->decl, scope, /*invisible=*/false, /*nested=*/true, + locus); + return b->decl; + } + else if (TREE_PUBLIC (x)) + { + if (visdecl && !b && duplicate_decls (x, visdecl)) + { + /* An external declaration at block scope referring to a + visible entity with internal linkage. The composite + type will already be correct for this scope, so we + just need to fall through to make the declaration in + this scope. */ + nested = true; + x = visdecl; + } + else + { + bind (name, x, external_scope, /*invisible=*/true, + /*nested=*/false, locus); + nested = true; + } + } + } + + if (TREE_CODE (x) != PARM_DECL) + warn_if_shadowing (x); + + skip_external_and_shadow_checks: + if (TREE_CODE (x) == TYPE_DECL) + { + /* So this is a typedef, set its underlying type. */ + set_underlying_type (x); + + /* If X is a typedef defined in the current function, record it + for the purpose of implementing the -Wunused-local-typedefs + warning. */ + record_locally_defined_typedef (x); + } + + bind (name, x, scope, /*invisible=*/false, nested, locus); + + /* If x's type is incomplete because it's based on a + structure or union which has not yet been fully declared, + attach it to that structure or union type, so we can go + back and complete the variable declaration later, if the + structure or union gets fully declared. + + If the input is erroneous, we can have error_mark in the type + slot (e.g. "f(void a, ...)") - that doesn't count as an + incomplete type. */ + if (TREE_TYPE (x) != error_mark_node + && !COMPLETE_TYPE_P (TREE_TYPE (x))) + { + tree element = TREE_TYPE (x); + + while (TREE_CODE (element) == ARRAY_TYPE) + element = TREE_TYPE (element); + element = TYPE_MAIN_VARIANT (element); + + if ((TREE_CODE (element) == RECORD_TYPE + || TREE_CODE (element) == UNION_TYPE) + && (TREE_CODE (x) != TYPE_DECL + || TREE_CODE (TREE_TYPE (x)) == ARRAY_TYPE) + && !COMPLETE_TYPE_P (element)) + C_TYPE_INCOMPLETE_VARS (element) + = tree_cons (NULL_TREE, x, C_TYPE_INCOMPLETE_VARS (element)); + } + return x; +} + +/* Record X as belonging to file scope. + This is used only internally by the Objective-C front end, + and is limited to its needs. duplicate_decls is not called; + if there is any preexisting decl for this identifier, it is an ICE. */ + +tree +pushdecl_top_level (tree x) +{ + tree name; + bool nested = false; + gcc_assert (TREE_CODE (x) == VAR_DECL || TREE_CODE (x) == CONST_DECL); + + name = DECL_NAME (x); + + gcc_assert (TREE_CODE (x) == CONST_DECL || !I_SYMBOL_BINDING (name)); + + if (TREE_PUBLIC (x)) + { + bind (name, x, external_scope, /*invisible=*/true, /*nested=*/false, + UNKNOWN_LOCATION); + nested = true; + } + if (file_scope) + bind (name, x, file_scope, /*invisible=*/false, nested, UNKNOWN_LOCATION); + + return x; +} + +static void +implicit_decl_warning (tree id, tree olddecl) +{ + if (warn_implicit_function_declaration) + { + bool warned; + + if (flag_isoc99) + warned = pedwarn (input_location, OPT_Wimplicit_function_declaration, + "implicit declaration of function %qE", id); + else + warned = warning (OPT_Wimplicit_function_declaration, + G_("implicit declaration of function %qE"), id); + if (olddecl && warned) + locate_old_decl (olddecl); + } +} + +/* Generate an implicit declaration for identifier FUNCTIONID at LOC as a + function of type int (). */ + +tree +implicitly_declare (location_t loc, tree functionid) +{ + struct c_binding *b; + tree decl = 0; + tree asmspec_tree; + + for (b = I_SYMBOL_BINDING (functionid); b; b = b->shadowed) + { + if (B_IN_SCOPE (b, external_scope)) + { + decl = b->decl; + break; + } + } + + if (decl) + { + if (decl == error_mark_node) + return decl; + + /* FIXME: Objective-C has weird not-really-builtin functions + which are supposed to be visible automatically. They wind up + in the external scope because they're pushed before the file + scope gets created. Catch this here and rebind them into the + file scope. */ + if (!DECL_BUILT_IN (decl) && DECL_IS_BUILTIN (decl)) + { + bind (functionid, decl, file_scope, + /*invisible=*/false, /*nested=*/true, + DECL_SOURCE_LOCATION (decl)); + return decl; + } + else + { + tree newtype = default_function_type; + if (b->u.type) + TREE_TYPE (decl) = b->u.type; + /* Implicit declaration of a function already declared + (somehow) in a different scope, or as a built-in. + If this is the first time this has happened, warn; + then recycle the old declaration but with the new type. */ + if (!C_DECL_IMPLICIT (decl)) + { + implicit_decl_warning (functionid, decl); + C_DECL_IMPLICIT (decl) = 1; + } + if (DECL_BUILT_IN (decl)) + { + newtype = build_type_attribute_variant (newtype, + TYPE_ATTRIBUTES + (TREE_TYPE (decl))); + if (!comptypes (newtype, TREE_TYPE (decl))) + { + warning_at (loc, 0, "incompatible implicit declaration of " + "built-in function %qD", decl); + newtype = TREE_TYPE (decl); + } + } + else + { + if (!comptypes (newtype, TREE_TYPE (decl))) + { + error_at (loc, "incompatible implicit declaration of function %qD", decl); + locate_old_decl (decl); + } + } + b->u.type = TREE_TYPE (decl); + TREE_TYPE (decl) = newtype; + bind (functionid, decl, current_scope, + /*invisible=*/false, /*nested=*/true, + DECL_SOURCE_LOCATION (decl)); + return decl; + } + } + + /* Not seen before. */ + decl = build_decl (loc, FUNCTION_DECL, functionid, default_function_type); + DECL_EXTERNAL (decl) = 1; + TREE_PUBLIC (decl) = 1; + C_DECL_IMPLICIT (decl) = 1; + implicit_decl_warning (functionid, 0); + asmspec_tree = maybe_apply_renaming_pragma (decl, /*asmname=*/NULL); + if (asmspec_tree) + set_user_assembler_name (decl, TREE_STRING_POINTER (asmspec_tree)); + + /* C89 says implicit declarations are in the innermost block. + So we record the decl in the standard fashion. */ + decl = pushdecl (decl); + + /* No need to call objc_check_decl here - it's a function type. */ + rest_of_decl_compilation (decl, 0, 0); + + /* Write a record describing this implicit function declaration + to the prototypes file (if requested). */ + gen_aux_info_record (decl, 0, 1, 0); + + /* Possibly apply some default attributes to this implicit declaration. */ + decl_attributes (&decl, NULL_TREE, 0); + + return decl; +} + +/* Issue an error message for a reference to an undeclared variable + ID, including a reference to a builtin outside of function-call + context. Establish a binding of the identifier to error_mark_node + in an appropriate scope, which will suppress further errors for the + same identifier. The error message should be given location LOC. */ +void +undeclared_variable (location_t loc, tree id) +{ + static bool already = false; + struct c_scope *scope; + + if (current_function_decl == 0) + { + error_at (loc, "%qE undeclared here (not in a function)", id); + scope = current_scope; + } + else + { + if (!objc_diagnose_private_ivar (id)) + error_at (loc, "%qE undeclared (first use in this function)", id); + if (!already) + { + inform (loc, "each undeclared identifier is reported only" + " once for each function it appears in"); + already = true; + } + + /* If we are parsing old-style parameter decls, current_function_decl + will be nonnull but current_function_scope will be null. */ + scope = current_function_scope ? current_function_scope : current_scope; + } + bind (id, error_mark_node, scope, /*invisible=*/false, /*nested=*/false, + UNKNOWN_LOCATION); +} + +/* Subroutine of lookup_label, declare_label, define_label: construct a + LABEL_DECL with all the proper frills. Also create a struct + c_label_vars initialized for the current scope. */ + +static tree +make_label (location_t location, tree name, bool defining, + struct c_label_vars **p_label_vars) +{ + tree label = build_decl (location, LABEL_DECL, name, void_type_node); + struct c_label_vars *label_vars; + + DECL_CONTEXT (label) = current_function_decl; + DECL_MODE (label) = VOIDmode; + + label_vars = ggc_alloc_c_label_vars (); + label_vars->shadowed = NULL; + set_spot_bindings (&label_vars->label_bindings, defining); + label_vars->decls_in_scope = make_tree_vector (); + label_vars->gotos = VEC_alloc (c_goto_bindings_p, gc, 0); + *p_label_vars = label_vars; + + return label; +} + +/* Get the LABEL_DECL corresponding to identifier NAME as a label. + Create one if none exists so far for the current function. + This is called when a label is used in a goto expression or + has its address taken. */ + +tree +lookup_label (tree name) +{ + tree label; + struct c_label_vars *label_vars; + + if (current_function_scope == 0) + { + error ("label %qE referenced outside of any function", name); + return 0; + } + + /* Use a label already defined or ref'd with this name, but not if + it is inherited from a containing function and wasn't declared + using __label__. */ + label = I_LABEL_DECL (name); + if (label && (DECL_CONTEXT (label) == current_function_decl + || C_DECLARED_LABEL_FLAG (label))) + { + /* If the label has only been declared, update its apparent + location to point here, for better diagnostics if it + turns out not to have been defined. */ + if (DECL_INITIAL (label) == NULL_TREE) + DECL_SOURCE_LOCATION (label) = input_location; + return label; + } + + /* No label binding for that identifier; make one. */ + label = make_label (input_location, name, false, &label_vars); + + /* Ordinary labels go in the current function scope. */ + bind_label (name, label, current_function_scope, label_vars); + + return label; +} + +/* Issue a warning about DECL for a goto statement at GOTO_LOC going + to LABEL. */ + +static void +warn_about_goto (location_t goto_loc, tree label, tree decl) +{ + if (variably_modified_type_p (TREE_TYPE (decl), NULL_TREE)) + error_at (goto_loc, + "jump into scope of identifier with variably modified type"); + else + warning_at (goto_loc, OPT_Wjump_misses_init, + "jump skips variable initialization"); + inform (DECL_SOURCE_LOCATION (label), "label %qD defined here", label); + inform (DECL_SOURCE_LOCATION (decl), "%qD declared here", decl); +} + +/* Look up a label because of a goto statement. This is like + lookup_label, but also issues any appropriate warnings. */ + +tree +lookup_label_for_goto (location_t loc, tree name) +{ + tree label; + struct c_label_vars *label_vars; + unsigned int ix; + tree decl; + + label = lookup_label (name); + if (label == NULL_TREE) + return NULL_TREE; + + /* If we are jumping to a different function, we can't issue any + useful warnings. */ + if (DECL_CONTEXT (label) != current_function_decl) + { + gcc_assert (C_DECLARED_LABEL_FLAG (label)); + return label; + } + + label_vars = I_LABEL_BINDING (name)->u.label; + + /* If the label has not yet been defined, then push this goto on a + list for possible later warnings. */ + if (label_vars->label_bindings.scope == NULL) + { + struct c_goto_bindings *g; + + g = ggc_alloc_c_goto_bindings (); + g->loc = loc; + set_spot_bindings (&g->goto_bindings, true); + VEC_safe_push (c_goto_bindings_p, gc, label_vars->gotos, g); + return label; + } + + /* If there are any decls in label_vars->decls_in_scope, then this + goto has missed the declaration of the decl. This happens for a + case like + int i = 1; + lab: + ... + goto lab; + Issue a warning or error. */ + FOR_EACH_VEC_ELT (tree, label_vars->decls_in_scope, ix, decl) + warn_about_goto (loc, label, decl); + + if (label_vars->label_bindings.left_stmt_expr) + { + error_at (loc, "jump into statement expression"); + inform (DECL_SOURCE_LOCATION (label), "label %qD defined here", label); + } + + return label; +} + +/* Make a label named NAME in the current function, shadowing silently + any that may be inherited from containing functions or containing + scopes. This is called for __label__ declarations. */ + +tree +declare_label (tree name) +{ + struct c_binding *b = I_LABEL_BINDING (name); + tree label; + struct c_label_vars *label_vars; + + /* Check to make sure that the label hasn't already been declared + at this scope */ + if (b && B_IN_CURRENT_SCOPE (b)) + { + error ("duplicate label declaration %qE", name); + locate_old_decl (b->decl); + + /* Just use the previous declaration. */ + return b->decl; + } + + label = make_label (input_location, name, false, &label_vars); + C_DECLARED_LABEL_FLAG (label) = 1; + + /* Declared labels go in the current scope. */ + bind_label (name, label, current_scope, label_vars); + + return label; +} + +/* When we define a label, issue any appropriate warnings if there are + any gotos earlier in the function which jump to this label. */ + +static void +check_earlier_gotos (tree label, struct c_label_vars* label_vars) +{ + unsigned int ix; + struct c_goto_bindings *g; + + FOR_EACH_VEC_ELT (c_goto_bindings_p, label_vars->gotos, ix, g) + { + struct c_binding *b; + struct c_scope *scope; + + /* We have a goto to this label. The goto is going forward. In + g->scope, the goto is going to skip any binding which was + defined after g->bindings_in_scope. */ + if (g->goto_bindings.scope->has_jump_unsafe_decl) + { + for (b = g->goto_bindings.scope->bindings; + b != g->goto_bindings.bindings_in_scope; + b = b->prev) + { + if (decl_jump_unsafe (b->decl)) + warn_about_goto (g->loc, label, b->decl); + } + } + + /* We also need to warn about decls defined in any scopes + between the scope of the label and the scope of the goto. */ + for (scope = label_vars->label_bindings.scope; + scope != g->goto_bindings.scope; + scope = scope->outer) + { + gcc_assert (scope != NULL); + if (scope->has_jump_unsafe_decl) + { + if (scope == label_vars->label_bindings.scope) + b = label_vars->label_bindings.bindings_in_scope; + else + b = scope->bindings; + for (; b != NULL; b = b->prev) + { + if (decl_jump_unsafe (b->decl)) + warn_about_goto (g->loc, label, b->decl); + } + } + } + + if (g->goto_bindings.stmt_exprs > 0) + { + error_at (g->loc, "jump into statement expression"); + inform (DECL_SOURCE_LOCATION (label), "label %qD defined here", + label); + } + } + + /* Now that the label is defined, we will issue warnings about + subsequent gotos to this label when we see them. */ + VEC_truncate (c_goto_bindings_p, label_vars->gotos, 0); + label_vars->gotos = NULL; +} + +/* 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 (location_t location, tree name) +{ + /* Find any preexisting label with this name. It is an error + if that label has already been defined in this function, or + if there is a containing function with a declared label with + the same name. */ + tree label = I_LABEL_DECL (name); + + if (label + && ((DECL_CONTEXT (label) == current_function_decl + && DECL_INITIAL (label) != 0) + || (DECL_CONTEXT (label) != current_function_decl + && C_DECLARED_LABEL_FLAG (label)))) + { + error_at (location, "duplicate label %qD", label); + locate_old_decl (label); + return 0; + } + else if (label && DECL_CONTEXT (label) == current_function_decl) + { + struct c_label_vars *label_vars = I_LABEL_BINDING (name)->u.label; + + /* The label has been used or declared already in this function, + but not defined. Update its location to point to this + definition. */ + DECL_SOURCE_LOCATION (label) = location; + set_spot_bindings (&label_vars->label_bindings, true); + + /* Issue warnings as required about any goto statements from + earlier in the function. */ + check_earlier_gotos (label, label_vars); + } + else + { + struct c_label_vars *label_vars; + + /* No label binding for that identifier; make one. */ + label = make_label (location, name, true, &label_vars); + + /* Ordinary labels go in the current function scope. */ + bind_label (name, label, current_function_scope, label_vars); + } + + if (!in_system_header && lookup_name (name)) + warning_at (location, OPT_Wtraditional, + "traditional C lacks a separate namespace " + "for labels, identifier %qE conflicts", name); + + /* Mark label as having been defined. */ + DECL_INITIAL (label) = error_mark_node; + return label; +} + +/* Get the bindings for a new switch statement. This is used to issue + warnings as appropriate for jumps from the switch to case or + default labels. */ + +struct c_spot_bindings * +c_get_switch_bindings (void) +{ + struct c_spot_bindings *switch_bindings; + + switch_bindings = XNEW (struct c_spot_bindings); + set_spot_bindings (switch_bindings, true); + return switch_bindings; +} + +void +c_release_switch_bindings (struct c_spot_bindings *bindings) +{ + gcc_assert (bindings->stmt_exprs == 0 && !bindings->left_stmt_expr); + XDELETE (bindings); +} + +/* This is called at the point of a case or default label to issue + warnings about decls as needed. It returns true if it found an + error, not just a warning. */ + +bool +c_check_switch_jump_warnings (struct c_spot_bindings *switch_bindings, + location_t switch_loc, location_t case_loc) +{ + bool saw_error; + struct c_scope *scope; + + saw_error = false; + for (scope = current_scope; + scope != switch_bindings->scope; + scope = scope->outer) + { + struct c_binding *b; + + gcc_assert (scope != NULL); + + if (!scope->has_jump_unsafe_decl) + continue; + + for (b = scope->bindings; b != NULL; b = b->prev) + { + if (decl_jump_unsafe (b->decl)) + { + if (variably_modified_type_p (TREE_TYPE (b->decl), NULL_TREE)) + { + saw_error = true; + error_at (case_loc, + ("switch jumps into scope of identifier with " + "variably modified type")); + } + else + warning_at (case_loc, OPT_Wjump_misses_init, + "switch jumps over variable initialization"); + inform (switch_loc, "switch starts here"); + inform (DECL_SOURCE_LOCATION (b->decl), "%qD declared here", + b->decl); + } + } + } + + if (switch_bindings->stmt_exprs > 0) + { + saw_error = true; + error_at (case_loc, "switch jumps into statement expression"); + inform (switch_loc, "switch starts here"); + } + + return saw_error; +} + +/* Given NAME, an IDENTIFIER_NODE, + return the structure (or union or enum) definition for that name. + If THISLEVEL_ONLY is nonzero, searches only the current_scope. + CODE says which kind of type the caller wants; + it is RECORD_TYPE or UNION_TYPE or ENUMERAL_TYPE. + If PLOC is not NULL and this returns non-null, it sets *PLOC to the + location where the tag was defined. + If the wrong kind of type is found, an error is reported. */ + +static tree +lookup_tag (enum tree_code code, tree name, int thislevel_only, + location_t *ploc) +{ + struct c_binding *b = I_TAG_BINDING (name); + int thislevel = 0; + + if (!b || !b->decl) + return 0; + + /* We only care about whether it's in this level if + thislevel_only was set or it might be a type clash. */ + if (thislevel_only || TREE_CODE (b->decl) != code) + { + /* For our purposes, a tag in the external scope is the same as + a tag in the file scope. (Primarily relevant to Objective-C + and its builtin structure tags, which get pushed before the + file scope is created.) */ + if (B_IN_CURRENT_SCOPE (b) + || (current_scope == file_scope && B_IN_EXTERNAL_SCOPE (b))) + thislevel = 1; + } + + if (thislevel_only && !thislevel) + return 0; + + if (TREE_CODE (b->decl) != code) + { + /* Definition isn't the kind we were looking for. */ + pending_invalid_xref = name; + pending_invalid_xref_location = input_location; + + /* If in the same binding level as a declaration as a tag + of a different type, this must not be allowed to + shadow that tag, so give the error immediately. + (For example, "struct foo; union foo;" is invalid.) */ + if (thislevel) + pending_xref_error (); + } + + if (ploc != NULL) + *ploc = b->locus; + + return b->decl; +} + +/* 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 (void) +{ + if (pending_invalid_xref != 0) + error_at (pending_invalid_xref_location, "%qE defined as wrong kind of tag", + pending_invalid_xref); + pending_invalid_xref = 0; +} + + +/* Look up NAME in the current scope 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 (tree name) +{ + struct c_binding *b = I_SYMBOL_BINDING (name); + if (b && !b->invisible) + { + maybe_record_typedef_use (b->decl); + return b->decl; + } + return 0; +} + +/* Similar to `lookup_name' but look only at the indicated scope. */ + +static tree +lookup_name_in_scope (tree name, struct c_scope *scope) +{ + struct c_binding *b; + + for (b = I_SYMBOL_BINDING (name); b; b = b->shadowed) + if (B_IN_SCOPE (b, scope)) + return b->decl; + return 0; +} + +/* Create the predefined scalar types of C, + and some nodes representing standard constants (0, 1, (void *) 0). + Initialize the global scope. + Make definitions for built-in primitive functions. */ + +void +c_init_decl_processing (void) +{ + location_t save_loc = input_location; + + /* Initialize reserved words for parser. */ + c_parse_init (); + + current_function_decl = 0; + + gcc_obstack_init (&parser_obstack); + + /* Make the externals scope. */ + push_scope (); + external_scope = current_scope; + + /* Declarations from c_common_nodes_and_builtins must not be associated + with this input file, lest we get differences between using and not + using preprocessed headers. */ + input_location = BUILTINS_LOCATION; + + c_common_nodes_and_builtins (); + + /* In C, comparisons and TRUTH_* expressions have type int. */ + truthvalue_type_node = integer_type_node; + truthvalue_true_node = integer_one_node; + truthvalue_false_node = integer_zero_node; + + /* Even in C99, which has a real boolean type. */ + pushdecl (build_decl (UNKNOWN_LOCATION, TYPE_DECL, get_identifier ("_Bool"), + boolean_type_node)); + + input_location = save_loc; + + pedantic_lvalues = true; + + make_fname_decl = c_make_fname_decl; + start_fname_decls (); +} + +/* Create the VAR_DECL at LOC for __FUNCTION__ etc. ID is the name to + give the decl, NAME is the initialization string and TYPE_DEP + indicates whether NAME depended on the type of the function. As we + don't yet implement delayed emission of static data, we mark the + decl as emitted so it is not placed in the output. Anything using + it must therefore pull out the STRING_CST initializer directly. + FIXME. */ + +static tree +c_make_fname_decl (location_t loc, tree id, int type_dep) +{ + const char *name = fname_as_string (type_dep); + tree decl, type, init; + size_t length = strlen (name); + + type = build_array_type (char_type_node, + build_index_type (size_int (length))); + type = c_build_qualified_type (type, TYPE_QUAL_CONST); + + decl = build_decl (loc, VAR_DECL, id, type); + + TREE_STATIC (decl) = 1; + TREE_READONLY (decl) = 1; + DECL_ARTIFICIAL (decl) = 1; + + init = build_string (length + 1, name); + free (CONST_CAST (char *, name)); + TREE_TYPE (init) = type; + DECL_INITIAL (decl) = init; + + TREE_USED (decl) = 1; + + if (current_function_decl + /* For invalid programs like this: + + void foo() + const char* p = __FUNCTION__; + + the __FUNCTION__ is believed to appear in K&R style function + parameter declarator. In that case we still don't have + function_scope. */ + && (!seen_error () || current_function_scope)) + { + DECL_CONTEXT (decl) = current_function_decl; + bind (id, decl, current_function_scope, + /*invisible=*/false, /*nested=*/false, UNKNOWN_LOCATION); + } + + finish_decl (decl, loc, init, NULL_TREE, NULL_TREE); + + return decl; +} + +tree +c_builtin_function (tree decl) +{ + tree type = TREE_TYPE (decl); + tree id = DECL_NAME (decl); + + const char *name = IDENTIFIER_POINTER (id); + C_DECL_BUILTIN_PROTOTYPE (decl) = prototype_p (type); + + /* Should never be called on a symbol with a preexisting meaning. */ + gcc_assert (!I_SYMBOL_BINDING (id)); + + bind (id, decl, external_scope, /*invisible=*/true, /*nested=*/false, + UNKNOWN_LOCATION); + + /* Builtins in the implementation namespace are made visible without + needing to be explicitly declared. See push_file_scope. */ + if (name[0] == '_' && (name[1] == '_' || ISUPPER (name[1]))) + { + DECL_CHAIN (decl) = visible_builtins; + visible_builtins = decl; + } + + return decl; +} + +tree +c_builtin_function_ext_scope (tree decl) +{ + tree type = TREE_TYPE (decl); + tree id = DECL_NAME (decl); + + const char *name = IDENTIFIER_POINTER (id); + C_DECL_BUILTIN_PROTOTYPE (decl) = prototype_p (type); + + /* Should never be called on a symbol with a preexisting meaning. */ + gcc_assert (!I_SYMBOL_BINDING (id)); + + bind (id, decl, external_scope, /*invisible=*/false, /*nested=*/false, + UNKNOWN_LOCATION); + + /* Builtins in the implementation namespace are made visible without + needing to be explicitly declared. See push_file_scope. */ + if (name[0] == '_' && (name[1] == '_' || ISUPPER (name[1]))) + { + DECL_CHAIN (decl) = visible_builtins; + visible_builtins = decl; + } + + return decl; +} + +/* 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 (const struct c_declspecs *declspecs) +{ + shadow_tag_warned (declspecs, 0); +} + +/* WARNED is 1 if we have done a pedwarn, 2 if we have done a warning, + but no pedwarn. */ +void +shadow_tag_warned (const struct c_declspecs *declspecs, int warned) +{ + bool found_tag = false; + + if (declspecs->type && !declspecs->default_int_p && !declspecs->typedef_p) + { + tree value = declspecs->type; + 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. */ + { + tree name = TYPE_NAME (value); + tree t; + + found_tag = true; + + if (declspecs->restrict_p) + { + error ("invalid use of %<restrict%>"); + warned = 1; + } + + if (name == 0) + { + if (warned != 1 && code != ENUMERAL_TYPE) + /* Empty unnamed enum OK */ + { + pedwarn (input_location, 0, + "unnamed struct/union that defines no instances"); + warned = 1; + } + } + else if (declspecs->typespec_kind != ctsk_tagdef + && declspecs->typespec_kind != ctsk_tagfirstref + && declspecs->storage_class != csc_none) + { + if (warned != 1) + pedwarn (input_location, 0, + "empty declaration with storage class specifier " + "does not redeclare tag"); + warned = 1; + pending_xref_error (); + } + else if (declspecs->typespec_kind != ctsk_tagdef + && declspecs->typespec_kind != ctsk_tagfirstref + && (declspecs->const_p + || declspecs->volatile_p + || declspecs->restrict_p + || declspecs->address_space)) + { + if (warned != 1) + pedwarn (input_location, 0, + "empty declaration with type qualifier " + "does not redeclare tag"); + warned = 1; + pending_xref_error (); + } + else if (declspecs->typespec_kind != ctsk_tagdef + && declspecs->typespec_kind != ctsk_tagfirstref + && declspecs->alignas_p) + { + if (warned != 1) + pedwarn (input_location, 0, + "empty declaration with %<_Alignas%> " + "does not redeclare tag"); + warned = 1; + pending_xref_error (); + } + else + { + pending_invalid_xref = 0; + t = lookup_tag (code, name, 1, NULL); + + if (t == 0) + { + t = make_node (code); + pushtag (input_location, name, t); + } + } + } + else + { + if (warned != 1 && !in_system_header) + { + pedwarn (input_location, 0, + "useless type name in empty declaration"); + warned = 1; + } + } + } + else if (warned != 1 && !in_system_header && declspecs->typedef_p) + { + pedwarn (input_location, 0, "useless type name in empty declaration"); + warned = 1; + } + + pending_invalid_xref = 0; + + if (declspecs->inline_p) + { + error ("%<inline%> in empty declaration"); + warned = 1; + } + + if (declspecs->noreturn_p) + { + error ("%<_Noreturn%> in empty declaration"); + warned = 1; + } + + if (current_scope == file_scope && declspecs->storage_class == csc_auto) + { + error ("%<auto%> in file-scope empty declaration"); + warned = 1; + } + + if (current_scope == file_scope && declspecs->storage_class == csc_register) + { + error ("%<register%> in file-scope empty declaration"); + warned = 1; + } + + if (!warned && !in_system_header && declspecs->storage_class != csc_none) + { + warning (0, "useless storage class specifier in empty declaration"); + warned = 2; + } + + if (!warned && !in_system_header && declspecs->thread_p) + { + warning (0, "useless %<__thread%> in empty declaration"); + warned = 2; + } + + if (!warned && !in_system_header && (declspecs->const_p + || declspecs->volatile_p + || declspecs->restrict_p + || declspecs->address_space)) + { + warning (0, "useless type qualifier in empty declaration"); + warned = 2; + } + + if (!warned && !in_system_header && declspecs->alignas_p) + { + warning (0, "useless %<_Alignas%> in empty declaration"); + warned = 2; + } + + if (warned != 1) + { + if (!found_tag) + pedwarn (input_location, 0, "empty declaration"); + } +} + + +/* Return the qualifiers from SPECS as a bitwise OR of TYPE_QUAL_* + bits. SPECS represents declaration specifiers that the grammar + only permits to contain type qualifiers and attributes. */ + +int +quals_from_declspecs (const struct c_declspecs *specs) +{ + int quals = ((specs->const_p ? TYPE_QUAL_CONST : 0) + | (specs->volatile_p ? TYPE_QUAL_VOLATILE : 0) + | (specs->restrict_p ? TYPE_QUAL_RESTRICT : 0) + | (ENCODE_QUAL_ADDR_SPACE (specs->address_space))); + gcc_assert (!specs->type + && !specs->decl_attr + && specs->typespec_word == cts_none + && specs->storage_class == csc_none + && !specs->typedef_p + && !specs->explicit_signed_p + && !specs->deprecated_p + && !specs->long_p + && !specs->long_long_p + && !specs->short_p + && !specs->signed_p + && !specs->unsigned_p + && !specs->complex_p + && !specs->inline_p + && !specs->noreturn_p + && !specs->thread_p); + return quals; +} + +/* Construct an array declarator. LOC is the location of the + beginning of the array (usually the opening brace). EXPR is the + expression inside [], or NULL_TREE. QUALS are the type qualifiers + inside the [] (to be applied to the pointer to which a parameter + array is converted). STATIC_P is true if "static" is inside the + [], false otherwise. VLA_UNSPEC_P is true if the array is [*], a + VLA of unspecified length which is nevertheless a complete type, + false otherwise. The field for the contained declarator is left to + be filled in by set_array_declarator_inner. */ + +struct c_declarator * +build_array_declarator (location_t loc, + tree expr, struct c_declspecs *quals, bool static_p, + bool vla_unspec_p) +{ + struct c_declarator *declarator = XOBNEW (&parser_obstack, + struct c_declarator); + declarator->id_loc = loc; + declarator->kind = cdk_array; + declarator->declarator = 0; + declarator->u.array.dimen = expr; + if (quals) + { + declarator->u.array.attrs = quals->attrs; + declarator->u.array.quals = quals_from_declspecs (quals); + } + else + { + declarator->u.array.attrs = NULL_TREE; + declarator->u.array.quals = 0; + } + declarator->u.array.static_p = static_p; + declarator->u.array.vla_unspec_p = vla_unspec_p; + if (!flag_isoc99) + { + if (static_p || quals != NULL) + pedwarn (loc, OPT_Wpedantic, + "ISO C90 does not support %<static%> or type " + "qualifiers in parameter array declarators"); + if (vla_unspec_p) + pedwarn (loc, OPT_Wpedantic, + "ISO C90 does not support %<[*]%> array declarators"); + } + if (vla_unspec_p) + { + if (!current_scope->parm_flag) + { + /* C99 6.7.5.2p4 */ + error_at (loc, "%<[*]%> not allowed in other than " + "function prototype scope"); + declarator->u.array.vla_unspec_p = false; + return NULL; + } + current_scope->had_vla_unspec = true; + } + return declarator; +} + +/* Set the contained declarator of an array declarator. DECL is the + declarator, as constructed by build_array_declarator; INNER is what + appears on the left of the []. */ + +struct c_declarator * +set_array_declarator_inner (struct c_declarator *decl, + struct c_declarator *inner) +{ + decl->declarator = inner; + return decl; +} + +/* INIT is a constructor that forms DECL's initializer. If the final + element initializes a flexible array field, add the size of that + initializer to DECL's size. */ + +static void +add_flexible_array_elts_to_size (tree decl, tree init) +{ + tree elt, type; + + if (VEC_empty (constructor_elt, CONSTRUCTOR_ELTS (init))) + return; + + elt = VEC_last (constructor_elt, CONSTRUCTOR_ELTS (init))->value; + type = TREE_TYPE (elt); + if (TREE_CODE (type) == ARRAY_TYPE + && TYPE_SIZE (type) == NULL_TREE + && TYPE_DOMAIN (type) != NULL_TREE + && TYPE_MAX_VALUE (TYPE_DOMAIN (type)) == NULL_TREE) + { + complete_array_type (&type, elt, false); + DECL_SIZE (decl) + = size_binop (PLUS_EXPR, DECL_SIZE (decl), TYPE_SIZE (type)); + DECL_SIZE_UNIT (decl) + = size_binop (PLUS_EXPR, DECL_SIZE_UNIT (decl), TYPE_SIZE_UNIT (type)); + } +} + +/* Decode a "typename", such as "int **", returning a ..._TYPE node. + Set *EXPR, if EXPR not NULL, to any expression to be evaluated + before the type name, and set *EXPR_CONST_OPERANDS, if + EXPR_CONST_OPERANDS not NULL, to indicate whether the type name may + appear in a constant expression. */ + +tree +groktypename (struct c_type_name *type_name, tree *expr, + bool *expr_const_operands) +{ + tree type; + tree attrs = type_name->specs->attrs; + + type_name->specs->attrs = NULL_TREE; + + type = grokdeclarator (type_name->declarator, type_name->specs, TYPENAME, + false, NULL, &attrs, expr, expr_const_operands, + DEPRECATED_NORMAL); + + /* Apply attributes. */ + decl_attributes (&type, attrs, 0); + + return type; +} + +/* 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. */ + +tree +start_decl (struct c_declarator *declarator, struct c_declspecs *declspecs, + bool initialized, tree attributes) +{ + tree decl; + tree tem; + tree expr = NULL_TREE; + enum deprecated_states deprecated_state = DEPRECATED_NORMAL; + + /* An object declared as __attribute__((deprecated)) suppresses + warnings of uses of other deprecated items. */ + if (lookup_attribute ("deprecated", attributes)) + deprecated_state = DEPRECATED_SUPPRESS; + + decl = grokdeclarator (declarator, declspecs, + NORMAL, initialized, NULL, &attributes, &expr, NULL, + deprecated_state); + if (!decl) + return 0; + + if (expr) + add_stmt (fold_convert (void_type_node, expr)); + + if (TREE_CODE (decl) != FUNCTION_DECL && MAIN_NAME_P (DECL_NAME (decl))) + warning (OPT_Wmain, "%q+D is usually a function", decl); + + 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: + error ("typedef %qD is initialized (use __typeof__ instead)", decl); + initialized = 0; + break; + + case FUNCTION_DECL: + error ("function %qD is initialized like a variable", decl); + initialized = 0; + break; + + case PARM_DECL: + /* DECL_INITIAL in a PARM_DECL is really DECL_ARG_TYPE. */ + error ("parameter %qD is initialized", decl); + initialized = 0; + break; + + default: + /* Don't allow initializations for incomplete types except for + arrays which might be completed by the initialization. */ + + /* This can happen if the array size is an undefined macro. + We already gave a warning, so we don't need another one. */ + if (TREE_TYPE (decl) == error_mark_node) + initialized = 0; + else if (COMPLETE_TYPE_P (TREE_TYPE (decl))) + { + /* 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 %qD has initializer but incomplete type", decl); + initialized = 0; + } + else if (C_DECL_VARIABLE_SIZE (decl)) + { + /* Although C99 is unclear about whether incomplete arrays + of VLAs themselves count as VLAs, it does not make + sense to permit them to be initialized given that + ordinary VLAs may not be initialized. */ + error ("variable-sized object may not be initialized"); + initialized = 0; + } + } + + if (initialized) + { + if (current_scope == file_scope) + 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, prototype_p (TREE_TYPE (decl))); + + /* 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, though this tends to break + a large body of code that grew up without this rule. + + Thread-local variables are never common, since there's no entrenched + body of code to break, and it allows more efficient variable references + in the presence of dynamic linking. */ + + if (TREE_CODE (decl) == VAR_DECL + && !initialized + && TREE_PUBLIC (decl) + && !DECL_THREAD_LOCAL_P (decl) + && !flag_no_common) + DECL_COMMON (decl) = 1; + + /* Set attributes here so if duplicate decl, will have proper attributes. */ + decl_attributes (&decl, attributes, 0); + + /* Handle gnu_inline attribute. */ + if (declspecs->inline_p + && !flag_gnu89_inline + && TREE_CODE (decl) == FUNCTION_DECL + && (lookup_attribute ("gnu_inline", DECL_ATTRIBUTES (decl)) + || current_function_decl)) + { + if (declspecs->storage_class == csc_auto && current_scope != file_scope) + ; + else if (declspecs->storage_class != csc_static) + DECL_EXTERNAL (decl) = !DECL_EXTERNAL (decl); + } + + if (TREE_CODE (decl) == FUNCTION_DECL + && targetm.calls.promote_prototypes (TREE_TYPE (decl))) + { + struct c_declarator *ce = declarator; + + if (ce->kind == cdk_pointer) + ce = declarator->declarator; + if (ce->kind == cdk_function) + { + tree args = ce->u.arg_info->parms; + for (; args; args = DECL_CHAIN (args)) + { + tree type = TREE_TYPE (args); + if (type && INTEGRAL_TYPE_P (type) + && TYPE_PRECISION (type) < TYPE_PRECISION (integer_type_node)) + DECL_ARG_TYPE (args) = integer_type_node; + } + } + } + + if (TREE_CODE (decl) == FUNCTION_DECL + && DECL_DECLARED_INLINE_P (decl) + && DECL_UNINLINABLE (decl) + && lookup_attribute ("noinline", DECL_ATTRIBUTES (decl))) + warning (OPT_Wattributes, "inline function %q+D given attribute noinline", + decl); + + /* C99 6.7.4p3: An inline definition of a function with external + linkage shall not contain a definition of a modifiable object + with static storage duration... */ + if (TREE_CODE (decl) == VAR_DECL + && current_scope != file_scope + && TREE_STATIC (decl) + && !TREE_READONLY (decl) + && DECL_DECLARED_INLINE_P (current_function_decl) + && DECL_EXTERNAL (current_function_decl)) + record_inline_static (input_location, current_function_decl, + decl, csi_modifiable); + + if (c_dialect_objc () + && (TREE_CODE (decl) == VAR_DECL + || TREE_CODE (decl) == FUNCTION_DECL)) + objc_check_global_decl (decl); + + /* Add this decl to the current scope. + TEM may equal DECL or it may be a previous decl of the same name. */ + tem = pushdecl (decl); + + if (initialized && DECL_EXTERNAL (tem)) + { + DECL_EXTERNAL (tem) = 0; + TREE_STATIC (tem) = 1; + } + + return tem; +} + +/* Subroutine of finish_decl. TYPE is the type of an uninitialized object + DECL or the non-array element type if DECL is an uninitialized array. + If that type has a const member, diagnose this. */ + +static void +diagnose_uninitialized_cst_member (tree decl, tree type) +{ + tree field; + for (field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field)) + { + tree field_type; + if (TREE_CODE (field) != FIELD_DECL) + continue; + field_type = strip_array_types (TREE_TYPE (field)); + + if (TYPE_QUALS (field_type) & TYPE_QUAL_CONST) + { + warning_at (DECL_SOURCE_LOCATION (decl), OPT_Wc___compat, + "uninitialized const member in %qT is invalid in C++", + strip_array_types (TREE_TYPE (decl))); + inform (DECL_SOURCE_LOCATION (field), "%qD should be initialized", field); + } + + if (TREE_CODE (field_type) == RECORD_TYPE + || TREE_CODE (field_type) == UNION_TYPE) + diagnose_uninitialized_cst_member (decl, field_type); + } +} + +/* Finish processing of a declaration; + install its initial value. + If ORIGTYPE is not NULL_TREE, it is the original type of INIT. + 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. + + INIT_LOC is the location of the initial value. */ + +void +finish_decl (tree decl, location_t init_loc, tree init, + tree origtype, tree asmspec_tree) +{ + tree type; + bool was_incomplete = (DECL_SIZE (decl) == 0); + const char *asmspec = 0; + + /* If a name was specified, get the string. */ + if ((TREE_CODE (decl) == FUNCTION_DECL || TREE_CODE (decl) == VAR_DECL) + && DECL_FILE_SCOPE_P (decl)) + asmspec_tree = maybe_apply_renaming_pragma (decl, asmspec_tree); + if (asmspec_tree) + asmspec = TREE_STRING_POINTER (asmspec_tree); + + if (TREE_CODE (decl) == VAR_DECL + && TREE_STATIC (decl) + && global_bindings_p ()) + /* So decl is a global variable. Record the types it uses + so that we can decide later to emit debug info for them. */ + record_types_used_by_current_var_decl (decl); + + /* 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 (init) + store_init_value (init_loc, decl, init, origtype); + + if (c_dialect_objc () && (TREE_CODE (decl) == VAR_DECL + || TREE_CODE (decl) == FUNCTION_DECL + || TREE_CODE (decl) == FIELD_DECL)) + objc_check_decl (decl); + + type = TREE_TYPE (decl); + + /* 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) + { + bool 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 (&TREE_TYPE (decl), DECL_INITIAL (decl), + do_default); + + /* Get the completed type made by complete_array_type. */ + type = TREE_TYPE (decl); + + switch (failure) + { + case 1: + error ("initializer fails to determine size of %q+D", decl); + break; + + case 2: + if (do_default) + error ("array size missing in %q+D", decl); + /* 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; + break; + + case 3: + error ("zero or negative size array %q+D", decl); + break; + + case 0: + /* For global variables, update the copy of the type that + exists in the binding. */ + if (TREE_PUBLIC (decl)) + { + struct c_binding *b_ext = I_SYMBOL_BINDING (DECL_NAME (decl)); + while (b_ext && !B_IN_EXTERNAL_SCOPE (b_ext)) + b_ext = b_ext->shadowed; + if (b_ext) + { + if (b_ext->u.type && comptypes (b_ext->u.type, type)) + b_ext->u.type = composite_type (b_ext->u.type, type); + else + b_ext->u.type = type; + } + } + break; + + default: + gcc_unreachable (); + } + + if (DECL_INITIAL (decl)) + TREE_TYPE (DECL_INITIAL (decl)) = type; + + relayout_decl (decl); + } + + if (TREE_CODE (decl) == VAR_DECL) + { + if (init && TREE_CODE (init) == CONSTRUCTOR) + add_flexible_array_elts_to_size (decl, init); + + if (DECL_SIZE (decl) == 0 && TREE_TYPE (decl) != error_mark_node + && COMPLETE_TYPE_P (TREE_TYPE (decl))) + layout_decl (decl, 0); + + if (DECL_SIZE (decl) == 0 + /* Don't give an error if we already gave one earlier. */ + && TREE_TYPE (decl) != error_mark_node + && (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. */ + ? (DECL_INITIAL (decl) != 0 + || !DECL_FILE_SCOPE_P (decl)) + /* An automatic variable with an incomplete type + is an error. */ + : !DECL_EXTERNAL (decl))) + { + error ("storage size of %q+D isn%'t known", decl); + 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 ("storage size of %q+D isn%'t constant", decl); + TREE_TYPE (decl) = error_mark_node; + } + } + + if (TREE_USED (type)) + { + TREE_USED (decl) = 1; + DECL_READ_P (decl) = 1; + } + } + + /* If this is a function and an assembler name is specified, reset DECL_RTL + so we can give it its new name. Also, update builtin_decl if it + was a normal built-in. */ + if (TREE_CODE (decl) == FUNCTION_DECL && asmspec) + { + if (DECL_BUILT_IN_CLASS (decl) == BUILT_IN_NORMAL) + set_builtin_user_assembler_name (decl, asmspec); + set_user_assembler_name (decl, asmspec); + } + + /* If #pragma weak was used, mark the decl weak now. */ + maybe_apply_pragma_weak (decl); + + /* 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) + { + /* Determine the ELF visibility. */ + if (TREE_PUBLIC (decl)) + c_determine_visibility (decl); + + /* This is a no-op in c-lang.c or something real in objc-act.c. */ + if (c_dialect_objc ()) + objc_check_decl (decl); + + if (asmspec) + { + /* If this is not a static variable, issue a warning. + It doesn't make any sense to give an ASMSPEC for an + ordinary, non-register local variable. Historically, + GCC has accepted -- but ignored -- the ASMSPEC in + this case. */ + if (!DECL_FILE_SCOPE_P (decl) + && TREE_CODE (decl) == VAR_DECL + && !C_DECL_REGISTER (decl) + && !TREE_STATIC (decl)) + warning (0, "ignoring asm-specifier for non-static local " + "variable %q+D", decl); + else + set_user_assembler_name (decl, asmspec); + } + + if (DECL_FILE_SCOPE_P (decl)) + { + if (DECL_INITIAL (decl) == NULL_TREE + || DECL_INITIAL (decl) == error_mark_node) + /* Don't output anything + when a tentative file-scope definition is seen. + But at end of compilation, do output code for them. */ + DECL_DEFER_OUTPUT (decl) = 1; + if (asmspec && C_DECL_REGISTER (decl)) + DECL_HARD_REGISTER (decl) = 1; + rest_of_decl_compilation (decl, true, 0); + } + else + { + /* In conjunction with an ASMSPEC, the `register' + keyword indicates that we should place the variable + in a particular register. */ + if (asmspec && C_DECL_REGISTER (decl)) + { + DECL_HARD_REGISTER (decl) = 1; + /* This cannot be done for a structure with volatile + fields, on which DECL_REGISTER will have been + reset. */ + if (!DECL_REGISTER (decl)) + error ("cannot put object with volatile field into register"); + } + + if (TREE_CODE (decl) != FUNCTION_DECL) + { + /* If we're building a variable sized type, and we might be + reachable other than via the top of the current binding + level, then create a new BIND_EXPR so that we deallocate + the object at the right time. */ + /* Note that DECL_SIZE can be null due to errors. */ + if (DECL_SIZE (decl) + && !TREE_CONSTANT (DECL_SIZE (decl)) + && STATEMENT_LIST_HAS_LABEL (cur_stmt_list)) + { + tree bind; + bind = build3 (BIND_EXPR, void_type_node, NULL, NULL, NULL); + TREE_SIDE_EFFECTS (bind) = 1; + add_stmt (bind); + BIND_EXPR_BODY (bind) = push_stmt_list (); + } + add_stmt (build_stmt (DECL_SOURCE_LOCATION (decl), + DECL_EXPR, decl)); + } + } + + + if (!DECL_FILE_SCOPE_P (decl)) + { + /* 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; + } + } + } + + if (TREE_CODE (decl) == TYPE_DECL) + { + if (!DECL_FILE_SCOPE_P (decl) + && variably_modified_type_p (TREE_TYPE (decl), NULL_TREE)) + add_stmt (build_stmt (DECL_SOURCE_LOCATION (decl), DECL_EXPR, decl)); + + rest_of_decl_compilation (decl, DECL_FILE_SCOPE_P (decl), 0); + } + + /* Install a cleanup (aka destructor) if one was given. */ + if (TREE_CODE (decl) == VAR_DECL && !TREE_STATIC (decl)) + { + tree attr = lookup_attribute ("cleanup", DECL_ATTRIBUTES (decl)); + if (attr) + { + tree cleanup_id = TREE_VALUE (TREE_VALUE (attr)); + tree cleanup_decl = lookup_name (cleanup_id); + tree cleanup; + VEC(tree,gc) *vec; + + /* Build "cleanup(&decl)" for the destructor. */ + cleanup = build_unary_op (input_location, ADDR_EXPR, decl, 0); + vec = VEC_alloc (tree, gc, 1); + VEC_quick_push (tree, vec, cleanup); + cleanup = build_function_call_vec (DECL_SOURCE_LOCATION (decl), + cleanup_decl, vec, NULL); + VEC_free (tree, gc, vec); + + /* Don't warn about decl unused; the cleanup uses it. */ + TREE_USED (decl) = 1; + TREE_USED (cleanup_decl) = 1; + DECL_READ_P (decl) = 1; + + push_cleanup (decl, cleanup, false); + } + } + + if (warn_cxx_compat + && TREE_CODE (decl) == VAR_DECL + && !DECL_EXTERNAL (decl) + && DECL_INITIAL (decl) == NULL_TREE) + { + type = strip_array_types (type); + if (TREE_READONLY (decl)) + warning_at (DECL_SOURCE_LOCATION (decl), OPT_Wc___compat, + "uninitialized const %qD is invalid in C++", decl); + else if ((TREE_CODE (type) == RECORD_TYPE + || TREE_CODE (type) == UNION_TYPE) + && C_TYPE_FIELDS_READONLY (type)) + diagnose_uninitialized_cst_member (decl, type); + } + + invoke_plugin_callbacks (PLUGIN_FINISH_DECL, decl); +} + +/* Given a parsed parameter declaration, decode it into a PARM_DECL. + EXPR is NULL or a pointer to an expression that needs to be + evaluated for the side effects of array size expressions in the + parameters. */ + +tree +grokparm (const struct c_parm *parm, tree *expr) +{ + tree attrs = parm->attrs; + tree decl = grokdeclarator (parm->declarator, parm->specs, PARM, false, + NULL, &attrs, expr, NULL, DEPRECATED_NORMAL); + + decl_attributes (&decl, attrs, 0); + + return decl; +} + +/* Given a parsed parameter declaration, decode it into a PARM_DECL + and push that on the current scope. EXPR is a pointer to an + expression that needs to be evaluated for the side effects of array + size expressions in the parameters. */ + +void +push_parm_decl (const struct c_parm *parm, tree *expr) +{ + tree attrs = parm->attrs; + tree decl; + + decl = grokdeclarator (parm->declarator, parm->specs, PARM, false, NULL, + &attrs, expr, NULL, DEPRECATED_NORMAL); + decl_attributes (&decl, attrs, 0); + + decl = pushdecl (decl); + + finish_decl (decl, input_location, NULL_TREE, NULL_TREE, NULL_TREE); +} + +/* Mark all the parameter declarations to date as forward decls. + Also diagnose use of this extension. */ + +void +mark_forward_parm_decls (void) +{ + struct c_binding *b; + + if (pedantic && !current_scope->warned_forward_parm_decls) + { + pedwarn (input_location, OPT_Wpedantic, + "ISO C forbids forward parameter declarations"); + current_scope->warned_forward_parm_decls = true; + } + + for (b = current_scope->bindings; b; b = b->prev) + if (TREE_CODE (b->decl) == PARM_DECL) + TREE_ASM_WRITTEN (b->decl) = 1; +} + +/* Build a COMPOUND_LITERAL_EXPR. TYPE is the type given in the compound + literal, which may be an incomplete array type completed by the + initializer; INIT is a CONSTRUCTOR at LOC that initializes the compound + literal. NON_CONST is true if the initializers contain something + that cannot occur in a constant expression. */ + +tree +build_compound_literal (location_t loc, tree type, tree init, bool non_const) +{ + /* We do not use start_decl here because we have a type, not a declarator; + and do not use finish_decl because the decl should be stored inside + the COMPOUND_LITERAL_EXPR rather than added elsewhere as a DECL_EXPR. */ + tree decl; + tree complit; + tree stmt; + + if (type == error_mark_node + || init == error_mark_node) + return error_mark_node; + + decl = build_decl (loc, VAR_DECL, NULL_TREE, type); + DECL_EXTERNAL (decl) = 0; + TREE_PUBLIC (decl) = 0; + TREE_STATIC (decl) = (current_scope == file_scope); + DECL_CONTEXT (decl) = current_function_decl; + TREE_USED (decl) = 1; + DECL_READ_P (decl) = 1; + TREE_TYPE (decl) = type; + TREE_READONLY (decl) = (TYPE_READONLY (type) + || (TREE_CODE (type) == ARRAY_TYPE + && TYPE_READONLY (TREE_TYPE (type)))); + store_init_value (loc, decl, init, NULL_TREE); + + if (TREE_CODE (type) == ARRAY_TYPE && !COMPLETE_TYPE_P (type)) + { + int failure = complete_array_type (&TREE_TYPE (decl), + DECL_INITIAL (decl), true); + gcc_assert (!failure); + + type = TREE_TYPE (decl); + TREE_TYPE (DECL_INITIAL (decl)) = type; + } + + if (type == error_mark_node || !COMPLETE_TYPE_P (type)) + { + c_incomplete_type_error (NULL_TREE, type); + return error_mark_node; + } + + stmt = build_stmt (DECL_SOURCE_LOCATION (decl), DECL_EXPR, decl); + complit = build1 (COMPOUND_LITERAL_EXPR, type, stmt); + TREE_SIDE_EFFECTS (complit) = 1; + + layout_decl (decl, 0); + + if (TREE_STATIC (decl)) + { + /* This decl needs a name for the assembler output. */ + set_compound_literal_name (decl); + DECL_DEFER_OUTPUT (decl) = 1; + DECL_COMDAT (decl) = 1; + DECL_ARTIFICIAL (decl) = 1; + DECL_IGNORED_P (decl) = 1; + pushdecl (decl); + rest_of_decl_compilation (decl, 1, 0); + } + + if (non_const) + { + complit = build2 (C_MAYBE_CONST_EXPR, type, NULL, complit); + C_MAYBE_CONST_EXPR_NON_CONST (complit) = 1; + } + + return complit; +} + +/* Check the type of a compound literal. Here we just check that it + is valid for C++. */ + +void +check_compound_literal_type (location_t loc, struct c_type_name *type_name) +{ + if (warn_cxx_compat + && (type_name->specs->typespec_kind == ctsk_tagdef + || type_name->specs->typespec_kind == ctsk_tagfirstref)) + warning_at (loc, OPT_Wc___compat, + "defining a type in a compound literal is invalid in C++"); +} + +/* Determine whether TYPE is a structure with a flexible array member, + or a union containing such a structure (possibly recursively). */ + +static bool +flexible_array_type_p (tree type) +{ + tree x; + switch (TREE_CODE (type)) + { + case RECORD_TYPE: + x = TYPE_FIELDS (type); + if (x == NULL_TREE) + return false; + while (DECL_CHAIN (x) != NULL_TREE) + x = DECL_CHAIN (x); + if (TREE_CODE (TREE_TYPE (x)) == ARRAY_TYPE + && TYPE_SIZE (TREE_TYPE (x)) == NULL_TREE + && TYPE_DOMAIN (TREE_TYPE (x)) != NULL_TREE + && TYPE_MAX_VALUE (TYPE_DOMAIN (TREE_TYPE (x))) == NULL_TREE) + return true; + return false; + case UNION_TYPE: + for (x = TYPE_FIELDS (type); x != NULL_TREE; x = DECL_CHAIN (x)) + { + if (flexible_array_type_p (TREE_TYPE (x))) + return true; + } + return false; + default: + return false; + } +} + +/* Performs sanity checks on the TYPE and WIDTH of the bit-field NAME, + replacing with appropriate values if they are invalid. */ +static void +check_bitfield_type_and_width (tree *type, tree *width, tree orig_name) +{ + tree type_mv; + unsigned int max_width; + unsigned HOST_WIDE_INT w; + const char *name = (orig_name + ? identifier_to_locale (IDENTIFIER_POINTER (orig_name)) + : _("<anonymous>")); + + /* Detect and ignore out of range field width and process valid + field widths. */ + if (!INTEGRAL_TYPE_P (TREE_TYPE (*width))) + { + error ("bit-field %qs width not an integer constant", name); + *width = integer_one_node; + } + else + { + if (TREE_CODE (*width) != INTEGER_CST) + { + *width = c_fully_fold (*width, false, NULL); + if (TREE_CODE (*width) == INTEGER_CST) + pedwarn (input_location, OPT_Wpedantic, + "bit-field %qs width not an integer constant expression", + name); + } + if (TREE_CODE (*width) != INTEGER_CST) + { + error ("bit-field %qs width not an integer constant", name); + *width = integer_one_node; + } + constant_expression_warning (*width); + if (tree_int_cst_sgn (*width) < 0) + { + error ("negative width in bit-field %qs", name); + *width = integer_one_node; + } + else if (integer_zerop (*width) && orig_name) + { + error ("zero width for bit-field %qs", name); + *width = integer_one_node; + } + } + + /* Detect invalid bit-field type. */ + if (TREE_CODE (*type) != INTEGER_TYPE + && TREE_CODE (*type) != BOOLEAN_TYPE + && TREE_CODE (*type) != ENUMERAL_TYPE) + { + error ("bit-field %qs has invalid type", name); + *type = unsigned_type_node; + } + + type_mv = TYPE_MAIN_VARIANT (*type); + if (!in_system_header + && type_mv != integer_type_node + && type_mv != unsigned_type_node + && type_mv != boolean_type_node) + pedwarn (input_location, OPT_Wpedantic, + "type of bit-field %qs is a GCC extension", name); + + max_width = TYPE_PRECISION (*type); + + if (0 < compare_tree_int (*width, max_width)) + { + error ("width of %qs exceeds its type", name); + w = max_width; + *width = build_int_cst (integer_type_node, w); + } + else + w = tree_low_cst (*width, 1); + + if (TREE_CODE (*type) == ENUMERAL_TYPE) + { + struct lang_type *lt = TYPE_LANG_SPECIFIC (*type); + if (!lt + || w < tree_int_cst_min_precision (lt->enum_min, TYPE_UNSIGNED (*type)) + || w < tree_int_cst_min_precision (lt->enum_max, TYPE_UNSIGNED (*type))) + warning (0, "%qs is narrower than values of its type", name); + } +} + + + +/* Print warning about variable length array if necessary. */ + +static void +warn_variable_length_array (tree name, tree size) +{ + int const_size = TREE_CONSTANT (size); + + if (!flag_isoc99 && pedantic && warn_vla != 0) + { + if (const_size) + { + if (name) + pedwarn (input_location, OPT_Wvla, + "ISO C90 forbids array %qE whose size " + "can%'t be evaluated", + name); + else + pedwarn (input_location, OPT_Wvla, "ISO C90 forbids array whose size " + "can%'t be evaluated"); + } + else + { + if (name) + pedwarn (input_location, OPT_Wvla, + "ISO C90 forbids variable length array %qE", + name); + else + pedwarn (input_location, OPT_Wvla, "ISO C90 forbids variable length array"); + } + } + else if (warn_vla > 0) + { + if (const_size) + { + if (name) + warning (OPT_Wvla, + "the size of array %qE can" + "%'t be evaluated", name); + else + warning (OPT_Wvla, + "the size of array can %'t be evaluated"); + } + else + { + if (name) + warning (OPT_Wvla, + "variable length array %qE is used", + name); + else + warning (OPT_Wvla, + "variable length array is used"); + } + } +} + +/* 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 c_declspecs structure for the declaration 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. + INITIALIZED is true if the decl has an initializer. + WIDTH is non-NULL for bit-fields, and is a pointer to an INTEGER_CST node + representing the width of the bit-field. + DECL_ATTRS points to the list of attributes that should be added to this + decl. Any nested attributes that belong on the decl itself will be + added to this list. + If EXPR is not NULL, any expressions that need to be evaluated as + part of evaluating variably modified types will be stored in *EXPR. + If EXPR_CONST_OPERANDS is not NULL, *EXPR_CONST_OPERANDS will be + set to indicate whether operands in *EXPR can be used in constant + expressions. + DEPRECATED_STATE is a deprecated_states value indicating whether + deprecation warnings should be suppressed. + + 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 (const struct c_declarator *declarator, + struct c_declspecs *declspecs, + enum decl_context decl_context, bool initialized, tree *width, + tree *decl_attrs, tree *expr, bool *expr_const_operands, + enum deprecated_states deprecated_state) +{ + tree type = declspecs->type; + bool threadp = declspecs->thread_p; + enum c_storage_class storage_class = declspecs->storage_class; + int constp; + int restrictp; + int volatilep; + int type_quals = TYPE_UNQUALIFIED; + tree name = NULL_TREE; + bool funcdef_flag = false; + bool funcdef_syntax = false; + bool size_varies = false; + tree decl_attr = declspecs->decl_attr; + int array_ptr_quals = TYPE_UNQUALIFIED; + tree array_ptr_attrs = NULL_TREE; + int array_parm_static = 0; + bool array_parm_vla_unspec_p = false; + tree returned_attrs = NULL_TREE; + bool bitfield = width != NULL; + tree element_type; + struct c_arg_info *arg_info = 0; + addr_space_t as1, as2, address_space; + location_t loc = UNKNOWN_LOCATION; + const char *errmsg; + tree expr_dummy; + bool expr_const_operands_dummy; + enum c_declarator_kind first_non_attr_kind; + unsigned int alignas_align = 0; + + if (TREE_CODE (type) == ERROR_MARK) + return error_mark_node; + if (expr == NULL) + expr = &expr_dummy; + if (expr_const_operands == NULL) + expr_const_operands = &expr_const_operands_dummy; + + *expr = declspecs->expr; + *expr_const_operands = declspecs->expr_const_operands; + + if (decl_context == FUNCDEF) + funcdef_flag = true, decl_context = NORMAL; + + /* Look inside a declarator for the name being declared + and get it as an IDENTIFIER_NODE, for an error message. */ + { + const struct c_declarator *decl = declarator; + + first_non_attr_kind = cdk_attrs; + while (decl) + switch (decl->kind) + { + case cdk_array: + loc = decl->id_loc; + /* FALL THRU. */ + + case cdk_function: + case cdk_pointer: + funcdef_syntax = (decl->kind == cdk_function); + decl = decl->declarator; + if (first_non_attr_kind == cdk_attrs) + first_non_attr_kind = decl->kind; + break; + + case cdk_attrs: + decl = decl->declarator; + break; + + case cdk_id: + loc = decl->id_loc; + if (decl->u.id) + name = decl->u.id; + if (first_non_attr_kind == cdk_attrs) + first_non_attr_kind = decl->kind; + decl = 0; + break; + + default: + gcc_unreachable (); + } + if (name == 0) + { + gcc_assert (decl_context == PARM + || decl_context == TYPENAME + || (decl_context == FIELD + && declarator->kind == cdk_id)); + gcc_assert (!initialized); + } + } + + /* A function definition's declarator must have the form of + a function declarator. */ + + if (funcdef_flag && !funcdef_syntax) + return 0; + + /* 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_scope->parm_flag) + decl_context = PARM; + + if (declspecs->deprecated_p && deprecated_state != DEPRECATED_SUPPRESS) + warn_deprecated_use (declspecs->type, declspecs->decl_attr); + + if ((decl_context == NORMAL || decl_context == FIELD) + && current_scope == file_scope + && variably_modified_type_p (type, NULL_TREE)) + { + if (name) + error_at (loc, "variably modified %qE at file scope", name); + else + error_at (loc, "variably modified field at file scope"); + type = integer_type_node; + } + + size_varies = C_TYPE_VARIABLE_SIZE (type) != 0; + + /* Diagnose defaulting to "int". */ + + if (declspecs->default_int_p && !in_system_header) + { + /* Issue a warning if this is an ISO C 99 program or if + -Wreturn-type and this is a function, or if -Wimplicit; + prefer the former warning since it is more explicit. */ + if ((warn_implicit_int || warn_return_type || flag_isoc99) + && funcdef_flag) + warn_about_return_type = 1; + else + { + if (name) + pedwarn_c99 (loc, flag_isoc99 ? 0 : OPT_Wimplicit_int, + "type defaults to %<int%> in declaration of %qE", + name); + else + pedwarn_c99 (input_location, flag_isoc99 ? 0 : OPT_Wimplicit_int, + "type defaults to %<int%> in type name"); + } + } + + /* Adjust the type if a bit-field is being declared, + -funsigned-bitfields applied and the type is not explicitly + "signed". */ + if (bitfield && !flag_signed_bitfields && !declspecs->explicit_signed_p + && TREE_CODE (type) == INTEGER_TYPE) + type = unsigned_type_for (type); + + /* Figure out the type qualifiers for the declaration. There are + two ways a declaration can become qualified. One is something + like `const int i' where the `const' is explicit. Another is + something like `typedef const int CI; CI i' where the type of the + declaration contains the `const'. A third possibility is that + there is a type qualifier on the element type of a typedefed + array type, in which case we should extract that qualifier so + that c_apply_type_quals_to_decl receives the full list of + qualifiers to work with (C90 is not entirely clear about whether + duplicate qualifiers should be diagnosed in this case, but it + seems most appropriate to do so). */ + element_type = strip_array_types (type); + constp = declspecs->const_p + TYPE_READONLY (element_type); + restrictp = declspecs->restrict_p + TYPE_RESTRICT (element_type); + volatilep = declspecs->volatile_p + TYPE_VOLATILE (element_type); + as1 = declspecs->address_space; + as2 = TYPE_ADDR_SPACE (element_type); + address_space = ADDR_SPACE_GENERIC_P (as1)? as2 : as1; + + if (pedantic && !flag_isoc99) + { + if (constp > 1) + pedwarn (loc, OPT_Wpedantic, "duplicate %<const%>"); + if (restrictp > 1) + pedwarn (loc, OPT_Wpedantic, "duplicate %<restrict%>"); + if (volatilep > 1) + pedwarn (loc, OPT_Wpedantic, "duplicate %<volatile%>"); + } + + if (!ADDR_SPACE_GENERIC_P (as1) && !ADDR_SPACE_GENERIC_P (as2) && as1 != as2) + error_at (loc, "conflicting named address spaces (%s vs %s)", + c_addr_space_name (as1), c_addr_space_name (as2)); + + if ((TREE_CODE (type) == ARRAY_TYPE + || first_non_attr_kind == cdk_array) + && TYPE_QUALS (element_type)) + type = TYPE_MAIN_VARIANT (type); + type_quals = ((constp ? TYPE_QUAL_CONST : 0) + | (restrictp ? TYPE_QUAL_RESTRICT : 0) + | (volatilep ? TYPE_QUAL_VOLATILE : 0) + | ENCODE_QUAL_ADDR_SPACE (address_space)); + + /* Warn about storage classes that are invalid for certain + kinds of declarations (parameters, typenames, etc.). */ + + if (funcdef_flag + && (threadp + || storage_class == csc_auto + || storage_class == csc_register + || storage_class == csc_typedef)) + { + if (storage_class == csc_auto) + pedwarn (loc, + (current_scope == file_scope) ? 0 : OPT_Wpedantic, + "function definition declared %<auto%>"); + if (storage_class == csc_register) + error_at (loc, "function definition declared %<register%>"); + if (storage_class == csc_typedef) + error_at (loc, "function definition declared %<typedef%>"); + if (threadp) + error_at (loc, "function definition declared %<__thread%>"); + threadp = false; + if (storage_class == csc_auto + || storage_class == csc_register + || storage_class == csc_typedef) + storage_class = csc_none; + } + else if (decl_context != NORMAL && (storage_class != csc_none || threadp)) + { + if (decl_context == PARM && storage_class == csc_register) + ; + else + { + switch (decl_context) + { + case FIELD: + if (name) + error_at (loc, "storage class specified for structure " + "field %qE", name); + else + error_at (loc, "storage class specified for structure field"); + break; + case PARM: + if (name) + error_at (loc, "storage class specified for parameter %qE", + name); + else + error_at (loc, "storage class specified for unnamed parameter"); + break; + default: + error_at (loc, "storage class specified for typename"); + break; + } + storage_class = csc_none; + threadp = false; + } + } + else if (storage_class == csc_extern + && initialized + && !funcdef_flag) + { + /* 'extern' with initialization is invalid if not at file scope. */ + if (current_scope == file_scope) + { + /* It is fine to have 'extern const' when compiling at C + and C++ intersection. */ + if (!(warn_cxx_compat && constp)) + warning_at (loc, 0, "%qE initialized and declared %<extern%>", + name); + } + else + error_at (loc, "%qE has both %<extern%> and initializer", name); + } + else if (current_scope == file_scope) + { + if (storage_class == csc_auto) + error_at (loc, "file-scope declaration of %qE specifies %<auto%>", + name); + if (pedantic && storage_class == csc_register) + pedwarn (input_location, OPT_Wpedantic, + "file-scope declaration of %qE specifies %<register%>", name); + } + else + { + if (storage_class == csc_extern && funcdef_flag) + error_at (loc, "nested function %qE declared %<extern%>", name); + else if (threadp && storage_class == csc_none) + { + error_at (loc, "function-scope %qE implicitly auto and declared " + "%<__thread%>", + name); + threadp = false; + } + } + + /* 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). + At each stage we maintain an unqualified version of the type + together with any qualifiers that should be applied to it with + c_build_qualified_type; this way, array types including + multidimensional array types are first built up in unqualified + form and then the qualified form is created with + TYPE_MAIN_VARIANT pointing to the unqualified form. */ + + while (declarator && declarator->kind != cdk_id) + { + if (type == error_mark_node) + { + declarator = declarator->declarator; + continue; + } + + /* Each level of DECLARATOR is either a cdk_array (for ...[..]), + a cdk_pointer (for *...), + a cdk_function (for ...(...)), + a cdk_attrs (for nested attributes), + or a cdk_id (for the name being declared + or the place in an absolute declarator + where the name was omitted). + For the last case, 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 (array_ptr_quals != TYPE_UNQUALIFIED + || array_ptr_attrs != NULL_TREE + || array_parm_static) + { + /* Only the innermost declarator (making a parameter be of + array type which is converted to pointer type) + may have static or type qualifiers. */ + error_at (loc, "static or type qualifiers in non-parameter array declarator"); + array_ptr_quals = TYPE_UNQUALIFIED; + array_ptr_attrs = NULL_TREE; + array_parm_static = 0; + } + + switch (declarator->kind) + { + case cdk_attrs: + { + /* A declarator with embedded attributes. */ + tree attrs = declarator->u.attrs; + const struct c_declarator *inner_decl; + int attr_flags = 0; + declarator = declarator->declarator; + inner_decl = declarator; + while (inner_decl->kind == cdk_attrs) + inner_decl = inner_decl->declarator; + if (inner_decl->kind == cdk_id) + attr_flags |= (int) ATTR_FLAG_DECL_NEXT; + else if (inner_decl->kind == cdk_function) + attr_flags |= (int) ATTR_FLAG_FUNCTION_NEXT; + else if (inner_decl->kind == cdk_array) + attr_flags |= (int) ATTR_FLAG_ARRAY_NEXT; + returned_attrs = decl_attributes (&type, + chainon (returned_attrs, attrs), + attr_flags); + break; + } + case cdk_array: + { + tree itype = NULL_TREE; + tree size = declarator->u.array.dimen; + /* The index is a signed object `sizetype' bits wide. */ + tree index_type = c_common_signed_type (sizetype); + + array_ptr_quals = declarator->u.array.quals; + array_ptr_attrs = declarator->u.array.attrs; + array_parm_static = declarator->u.array.static_p; + array_parm_vla_unspec_p = declarator->u.array.vla_unspec_p; + + declarator = declarator->declarator; + + /* Check for some types that there cannot be arrays of. */ + + if (VOID_TYPE_P (type)) + { + if (name) + error_at (loc, "declaration of %qE as array of voids", name); + else + error_at (loc, "declaration of type name as array of voids"); + type = error_mark_node; + } + + if (TREE_CODE (type) == FUNCTION_TYPE) + { + if (name) + error_at (loc, "declaration of %qE as array of functions", + name); + else + error_at (loc, "declaration of type name as array of " + "functions"); + type = error_mark_node; + } + + if (pedantic && !in_system_header && flexible_array_type_p (type)) + pedwarn (loc, OPT_Wpedantic, + "invalid use of structure with flexible array member"); + + if (size == error_mark_node) + type = error_mark_node; + + if (type == error_mark_node) + continue; + + /* 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) + { + bool size_maybe_const = true; + bool size_int_const = (TREE_CODE (size) == INTEGER_CST + && !TREE_OVERFLOW (size)); + bool this_size_varies = false; + + /* Strip NON_LVALUE_EXPRs since we aren't using as an + lvalue. */ + STRIP_TYPE_NOPS (size); + + if (!INTEGRAL_TYPE_P (TREE_TYPE (size))) + { + if (name) + error_at (loc, "size of array %qE has non-integer type", + name); + else + error_at (loc, + "size of unnamed array has non-integer type"); + size = integer_one_node; + } + + size = c_fully_fold (size, false, &size_maybe_const); + + if (pedantic && size_maybe_const && integer_zerop (size)) + { + if (name) + pedwarn (loc, OPT_Wpedantic, + "ISO C forbids zero-size array %qE", name); + else + pedwarn (loc, OPT_Wpedantic, + "ISO C forbids zero-size array"); + } + + if (TREE_CODE (size) == INTEGER_CST && size_maybe_const) + { + constant_expression_warning (size); + if (tree_int_cst_sgn (size) < 0) + { + if (name) + error_at (loc, "size of array %qE is negative", name); + else + error_at (loc, "size of unnamed array is negative"); + size = integer_one_node; + } + /* Handle a size folded to an integer constant but + not an integer constant expression. */ + if (!size_int_const) + { + /* If this is a file scope declaration of an + ordinary identifier, this is invalid code; + diagnosing it here and not subsequently + treating the type as variable-length avoids + more confusing diagnostics later. */ + if ((decl_context == NORMAL || decl_context == FIELD) + && current_scope == file_scope) + pedwarn (input_location, 0, + "variably modified %qE at file scope", + name); + else + this_size_varies = size_varies = true; + warn_variable_length_array (name, size); + } + } + else if ((decl_context == NORMAL || decl_context == FIELD) + && current_scope == file_scope) + { + error_at (loc, "variably modified %qE at file scope", 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. */ + this_size_varies = size_varies = true; + warn_variable_length_array (name, size); + } + + if (integer_zerop (size) && !this_size_varies) + { + /* A zero-length array cannot be represented with + an unsigned index type, which is what we'll + get with build_index_type. Create an + open-ended range instead. */ + itype = build_range_type (sizetype, size, NULL_TREE); + } + else + { + /* Arrange for the SAVE_EXPR on the inside of the + MINUS_EXPR, which allows the -1 to get folded + with the +1 that happens when building TYPE_SIZE. */ + if (size_varies) + size = save_expr (size); + if (this_size_varies && TREE_CODE (size) == INTEGER_CST) + size = build2 (COMPOUND_EXPR, TREE_TYPE (size), + integer_zero_node, size); + + /* Compute the maximum valid index, that is, size + - 1. Do the calculation in index_type, so that + if it is a variable the computations will be + done in the proper mode. */ + itype = fold_build2_loc (loc, MINUS_EXPR, index_type, + convert (index_type, size), + convert (index_type, + size_one_node)); + + /* The above overflows when size does not fit + in index_type. + ??? While a size of INT_MAX+1 technically shouldn't + cause an overflow (because we subtract 1), handling + this case seems like an unnecessary complication. */ + if (TREE_CODE (size) == INTEGER_CST + && !int_fits_type_p (size, index_type)) + { + if (name) + error_at (loc, "size of array %qE is too large", + name); + else + error_at (loc, "size of unnamed array is too large"); + type = error_mark_node; + continue; + } + + itype = build_index_type (itype); + } + if (this_size_varies) + { + if (*expr) + *expr = build2 (COMPOUND_EXPR, TREE_TYPE (size), + *expr, size); + else + *expr = size; + *expr_const_operands &= size_maybe_const; + } + } + else if (decl_context == FIELD) + { + bool flexible_array_member = false; + if (array_parm_vla_unspec_p) + /* Field names can in fact have function prototype + scope so [*] is disallowed here through making + the field variably modified, not through being + something other than a declaration with function + prototype scope. */ + size_varies = true; + else + { + const struct c_declarator *t = declarator; + while (t->kind == cdk_attrs) + t = t->declarator; + flexible_array_member = (t->kind == cdk_id); + } + if (flexible_array_member + && pedantic && !flag_isoc99 && !in_system_header) + pedwarn (loc, OPT_Wpedantic, + "ISO C90 does not support flexible array members"); + + /* ISO C99 Flexible array members are effectively + identical to GCC's zero-length array extension. */ + if (flexible_array_member || array_parm_vla_unspec_p) + itype = build_range_type (sizetype, size_zero_node, + NULL_TREE); + } + else if (decl_context == PARM) + { + if (array_parm_vla_unspec_p) + { + itype = build_range_type (sizetype, size_zero_node, NULL_TREE); + size_varies = true; + } + } + else if (decl_context == TYPENAME) + { + if (array_parm_vla_unspec_p) + { + /* C99 6.7.5.2p4 */ + warning (0, "%<[*]%> not in a declaration"); + /* We use this to avoid messing up with incomplete + array types of the same type, that would + otherwise be modified below. */ + itype = build_range_type (sizetype, size_zero_node, + NULL_TREE); + size_varies = true; + } + } + + /* Complain about arrays of incomplete types. */ + if (!COMPLETE_TYPE_P (type)) + { + error_at (loc, "array type has incomplete element type"); + type = error_mark_node; + } + else + /* When itype is NULL, a shared incomplete array type is + returned for all array of a given type. Elsewhere we + make sure we don't complete that type before copying + it, but here we want to make sure we don't ever + modify the shared type, so we gcc_assert (itype) + below. */ + { + addr_space_t as = DECODE_QUAL_ADDR_SPACE (type_quals); + if (!ADDR_SPACE_GENERIC_P (as) && as != TYPE_ADDR_SPACE (type)) + type = build_qualified_type (type, + ENCODE_QUAL_ADDR_SPACE (as)); + + type = build_array_type (type, itype); + } + + if (type != error_mark_node) + { + if (size_varies) + { + /* It is ok to modify type here even if itype is + NULL: if size_varies, we're in a + multi-dimensional array and the inner type has + variable size, so the enclosing shared array type + must too. */ + if (size && TREE_CODE (size) == INTEGER_CST) + type + = build_distinct_type_copy (TYPE_MAIN_VARIANT (type)); + C_TYPE_VARIABLE_SIZE (type) = 1; + } + + /* The GCC extension for zero-length arrays differs from + ISO flexible array members in that sizeof yields + zero. */ + if (size && integer_zerop (size)) + { + gcc_assert (itype); + type = build_distinct_type_copy (TYPE_MAIN_VARIANT (type)); + TYPE_SIZE (type) = bitsize_zero_node; + TYPE_SIZE_UNIT (type) = size_zero_node; + SET_TYPE_STRUCTURAL_EQUALITY (type); + } + if (array_parm_vla_unspec_p) + { + gcc_assert (itype); + /* The type is complete. C99 6.7.5.2p4 */ + type = build_distinct_type_copy (TYPE_MAIN_VARIANT (type)); + TYPE_SIZE (type) = bitsize_zero_node; + TYPE_SIZE_UNIT (type) = size_zero_node; + SET_TYPE_STRUCTURAL_EQUALITY (type); + } + } + + if (decl_context != PARM + && (array_ptr_quals != TYPE_UNQUALIFIED + || array_ptr_attrs != NULL_TREE + || array_parm_static)) + { + error_at (loc, "static or type qualifiers in non-parameter array declarator"); + array_ptr_quals = TYPE_UNQUALIFIED; + array_ptr_attrs = NULL_TREE; + array_parm_static = 0; + } + break; + } + case cdk_function: + { + /* Say it's a definition only for the declarator closest + to the identifier, apart possibly from some + attributes. */ + bool really_funcdef = false; + tree arg_types; + if (funcdef_flag) + { + const struct c_declarator *t = declarator->declarator; + while (t->kind == cdk_attrs) + t = t->declarator; + really_funcdef = (t->kind == cdk_id); + } + + /* Declaring a function type. Make sure we have a valid + type for the function to return. */ + if (type == error_mark_node) + continue; + + size_varies = false; + + /* Warn about some types functions can't return. */ + if (TREE_CODE (type) == FUNCTION_TYPE) + { + if (name) + error_at (loc, "%qE declared as function returning a " + "function", name); + else + error_at (loc, "type name declared as function " + "returning a function"); + type = integer_type_node; + } + if (TREE_CODE (type) == ARRAY_TYPE) + { + if (name) + error_at (loc, "%qE declared as function returning an array", + name); + else + error_at (loc, "type name declared as function returning " + "an array"); + type = integer_type_node; + } + errmsg = targetm.invalid_return_type (type); + if (errmsg) + { + error (errmsg); + type = integer_type_node; + } + + /* Construct the function type and go to the next + inner layer of declarator. */ + arg_info = declarator->u.arg_info; + arg_types = grokparms (arg_info, really_funcdef); + + /* Type qualifiers before the return type of the function + qualify the return type, not the function type. */ + if (type_quals) + { + /* Type qualifiers on a function return type are + normally permitted by the standard but have no + effect, so give a warning at -Wreturn-type. + Qualifiers on a void return type are banned on + function definitions in ISO C; GCC used to used + them for noreturn functions. */ + if (VOID_TYPE_P (type) && really_funcdef) + pedwarn (loc, 0, + "function definition has qualified void return type"); + else + warning_at (loc, OPT_Wignored_qualifiers, + "type qualifiers ignored on function return type"); + + type = c_build_qualified_type (type, type_quals); + } + type_quals = TYPE_UNQUALIFIED; + + type = build_function_type (type, arg_types); + declarator = declarator->declarator; + + /* 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. */ + { + c_arg_tag *tag; + unsigned ix; + + FOR_EACH_VEC_ELT_REVERSE (c_arg_tag, arg_info->tags, ix, tag) + TYPE_CONTEXT (tag->type) = type; + } + break; + } + case cdk_pointer: + { + /* Merge any constancy or volatility into the target type + for the pointer. */ + + if (pedantic && TREE_CODE (type) == FUNCTION_TYPE + && type_quals) + pedwarn (loc, OPT_Wpedantic, + "ISO C forbids qualified function types"); + if (type_quals) + type = c_build_qualified_type (type, type_quals); + size_varies = false; + + /* When the pointed-to type involves components of variable size, + care must be taken to ensure that the size evaluation code is + emitted early enough to dominate all the possible later uses + and late enough for the variables on which it depends to have + been assigned. + + This is expected to happen automatically when the pointed-to + type has a name/declaration of it's own, but special attention + is required if the type is anonymous. + + We handle the NORMAL and FIELD contexts here by attaching an + artificial TYPE_DECL to such pointed-to type. This forces the + sizes evaluation at a safe point and ensures it is not deferred + until e.g. within a deeper conditional context. + + We expect nothing to be needed here for PARM or TYPENAME. + Pushing a TYPE_DECL at this point for TYPENAME would actually + be incorrect, as we might be in the middle of an expression + with side effects on the pointed-to type size "arguments" prior + to the pointer declaration point and the fake TYPE_DECL in the + enclosing context would force the size evaluation prior to the + side effects. */ + + if (!TYPE_NAME (type) + && (decl_context == NORMAL || decl_context == FIELD) + && variably_modified_type_p (type, NULL_TREE)) + { + tree decl = build_decl (loc, TYPE_DECL, NULL_TREE, type); + DECL_ARTIFICIAL (decl) = 1; + pushdecl (decl); + finish_decl (decl, loc, NULL_TREE, NULL_TREE, NULL_TREE); + TYPE_NAME (type) = decl; + } + + type = c_build_pointer_type (type); + + /* Process type qualifiers (such as const or volatile) + that were given inside the `*'. */ + type_quals = declarator->u.pointer_quals; + + declarator = declarator->declarator; + break; + } + default: + gcc_unreachable (); + } + } + *decl_attrs = chainon (returned_attrs, *decl_attrs); + + /* Now TYPE has the actual type, apart from any qualifiers in + TYPE_QUALS. */ + + /* Warn about address space used for things other than static memory or + pointers. */ + address_space = DECODE_QUAL_ADDR_SPACE (type_quals); + if (!ADDR_SPACE_GENERIC_P (address_space)) + { + if (decl_context == NORMAL) + { + switch (storage_class) + { + case csc_auto: + error ("%qs combined with %<auto%> qualifier for %qE", + c_addr_space_name (address_space), name); + break; + case csc_register: + error ("%qs combined with %<register%> qualifier for %qE", + c_addr_space_name (address_space), name); + break; + case csc_none: + if (current_function_scope) + { + error ("%qs specified for auto variable %qE", + c_addr_space_name (address_space), name); + break; + } + break; + case csc_static: + case csc_extern: + case csc_typedef: + break; + default: + gcc_unreachable (); + } + } + else if (decl_context == PARM && TREE_CODE (type) != ARRAY_TYPE) + { + if (name) + error ("%qs specified for parameter %qE", + c_addr_space_name (address_space), name); + else + error ("%qs specified for unnamed parameter", + c_addr_space_name (address_space)); + } + else if (decl_context == FIELD) + { + if (name) + error ("%qs specified for structure field %qE", + c_addr_space_name (address_space), name); + else + error ("%qs specified for structure field", + c_addr_space_name (address_space)); + } + } + + /* Check the type and width of a bit-field. */ + if (bitfield) + check_bitfield_type_and_width (&type, width, name); + + /* Reject invalid uses of _Alignas. */ + if (declspecs->alignas_p) + { + if (storage_class == csc_typedef) + error_at (loc, "alignment specified for typedef %qE", name); + else if (storage_class == csc_register) + error_at (loc, "alignment specified for %<register%> object %qE", + name); + else if (decl_context == PARM) + { + if (name) + error_at (loc, "alignment specified for parameter %qE", name); + else + error_at (loc, "alignment specified for unnamed parameter"); + } + else if (bitfield) + { + if (name) + error_at (loc, "alignment specified for bit-field %qE", name); + else + error_at (loc, "alignment specified for unnamed bit-field"); + } + else if (TREE_CODE (type) == FUNCTION_TYPE) + error_at (loc, "alignment specified for function %qE", name); + else if (declspecs->align_log != -1) + { + alignas_align = 1U << declspecs->align_log; + if (alignas_align < TYPE_ALIGN_UNIT (type)) + { + if (name) + error_at (loc, "%<_Alignas%> specifiers cannot reduce " + "alignment of %qE", name); + else + error_at (loc, "%<_Alignas%> specifiers cannot reduce " + "alignment of unnamed field"); + alignas_align = 0; + } + } + } + + /* Did array size calculations overflow or does the array cover more + than half of the address-space? */ + if (TREE_CODE (type) == ARRAY_TYPE + && COMPLETE_TYPE_P (type) + && TREE_CODE (TYPE_SIZE_UNIT (type)) == INTEGER_CST + && ! valid_constant_size_p (TYPE_SIZE_UNIT (type))) + { + if (name) + error_at (loc, "size of array %qE is too large", name); + else + error_at (loc, "size of unnamed array is too large"); + /* If we proceed with the array type as it is, we'll eventually + crash in tree_low_cst(). */ + type = error_mark_node; + } + + /* If this is declaring a typedef name, return a TYPE_DECL. */ + + if (storage_class == csc_typedef) + { + tree decl; + if (pedantic && TREE_CODE (type) == FUNCTION_TYPE + && type_quals) + pedwarn (loc, OPT_Wpedantic, + "ISO C forbids qualified function types"); + if (type_quals) + type = c_build_qualified_type (type, type_quals); + decl = build_decl (declarator->id_loc, + TYPE_DECL, declarator->u.id, type); + if (declspecs->explicit_signed_p) + C_TYPEDEF_EXPLICITLY_SIGNED (decl) = 1; + if (declspecs->inline_p) + pedwarn (loc, 0,"typedef %q+D declared %<inline%>", decl); + if (declspecs->noreturn_p) + pedwarn (loc, 0,"typedef %q+D declared %<_Noreturn%>", decl); + + if (warn_cxx_compat && declarator->u.id != NULL_TREE) + { + struct c_binding *b = I_TAG_BINDING (declarator->u.id); + + if (b != NULL + && b->decl != NULL_TREE + && (B_IN_CURRENT_SCOPE (b) + || (current_scope == file_scope && B_IN_EXTERNAL_SCOPE (b))) + && TYPE_MAIN_VARIANT (b->decl) != TYPE_MAIN_VARIANT (type)) + { + warning_at (declarator->id_loc, OPT_Wc___compat, + ("using %qD as both a typedef and a tag is " + "invalid in C++"), + decl); + if (b->locus != UNKNOWN_LOCATION) + inform (b->locus, "originally defined here"); + } + } + + return decl; + } + + /* 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 + and fields. */ + gcc_assert (storage_class == csc_none && !threadp + && !declspecs->inline_p && !declspecs->noreturn_p); + if (pedantic && TREE_CODE (type) == FUNCTION_TYPE + && type_quals) + pedwarn (loc, OPT_Wpedantic, + "ISO C forbids const or volatile function types"); + if (type_quals) + type = c_build_qualified_type (type, type_quals); + return type; + } + + if (pedantic && decl_context == FIELD + && variably_modified_type_p (type, NULL_TREE)) + { + /* C99 6.7.2.1p8 */ + pedwarn (loc, OPT_Wpedantic, "a member of a structure or union cannot " + "have a variably modified 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 (VOID_TYPE_P (type) && decl_context != PARM + && !((decl_context != FIELD && TREE_CODE (type) != FUNCTION_TYPE) + && (storage_class == csc_extern + || (current_scope == file_scope + && !(storage_class == csc_static + || storage_class == csc_register))))) + { + error_at (loc, "variable or field %qE 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. */ + + { + tree decl; + + if (decl_context == PARM) + { + tree promoted_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 = c_build_pointer_type (type); + type_quals = array_ptr_quals; + if (type_quals) + type = c_build_qualified_type (type, type_quals); + + /* We don't yet implement attributes in this context. */ + if (array_ptr_attrs != NULL_TREE) + warning_at (loc, OPT_Wattributes, + "attributes in parameter array declarator ignored"); + + size_varies = false; + } + else if (TREE_CODE (type) == FUNCTION_TYPE) + { + if (type_quals) + pedwarn (loc, OPT_Wpedantic, + "ISO C forbids qualified function types"); + if (type_quals) + type = c_build_qualified_type (type, type_quals); + type = c_build_pointer_type (type); + type_quals = TYPE_UNQUALIFIED; + } + else if (type_quals) + type = c_build_qualified_type (type, type_quals); + + decl = build_decl (declarator->id_loc, + PARM_DECL, declarator->u.id, 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. */ + + if (type == error_mark_node) + promoted_type = type; + else + promoted_type = c_type_promotes_to (type); + + DECL_ARG_TYPE (decl) = promoted_type; + if (declspecs->inline_p) + pedwarn (loc, 0, "parameter %q+D declared %<inline%>", decl); + if (declspecs->noreturn_p) + pedwarn (loc, 0, "parameter %q+D declared %<_Noreturn%>", decl); + } + else if (decl_context == FIELD) + { + /* Note that the grammar rejects storage classes in typenames + and fields. */ + gcc_assert (storage_class == csc_none && !threadp + && !declspecs->inline_p && !declspecs->noreturn_p); + + /* Structure field. It may not be a function. */ + + if (TREE_CODE (type) == FUNCTION_TYPE) + { + error_at (loc, "field %qE declared as a function", name); + type = build_pointer_type (type); + } + else if (TREE_CODE (type) != ERROR_MARK + && !COMPLETE_OR_UNBOUND_ARRAY_TYPE_P (type)) + { + if (name) + error_at (loc, "field %qE has incomplete type", name); + else + error_at (loc, "unnamed field has incomplete type"); + type = error_mark_node; + } + type = c_build_qualified_type (type, type_quals); + decl = build_decl (declarator->id_loc, + FIELD_DECL, declarator->u.id, type); + DECL_NONADDRESSABLE_P (decl) = bitfield; + if (bitfield && !declarator->u.id) + TREE_NO_WARNING (decl) = 1; + + if (size_varies) + C_DECL_VARIABLE_SIZE (decl) = 1; + } + else if (TREE_CODE (type) == FUNCTION_TYPE) + { + if (storage_class == csc_register || threadp) + { + error_at (loc, "invalid storage class for function %qE", name); + } + else if (current_scope != file_scope) + { + /* Function declaration not at file scope. Storage + classes other than `extern' are not allowed, C99 + 6.7.1p5, and `extern' makes no difference. However, + GCC allows 'auto', perhaps with 'inline', to support + nested functions. */ + if (storage_class == csc_auto) + pedwarn (loc, OPT_Wpedantic, + "invalid storage class for function %qE", name); + else if (storage_class == csc_static) + { + error_at (loc, "invalid storage class for function %qE", name); + if (funcdef_flag) + storage_class = declspecs->storage_class = csc_none; + else + return 0; + } + } + + decl = build_decl (declarator->id_loc, + FUNCTION_DECL, declarator->u.id, type); + decl = build_decl_attribute_variant (decl, decl_attr); + + if (pedantic && type_quals && !DECL_IN_SYSTEM_HEADER (decl)) + pedwarn (loc, OPT_Wpedantic, + "ISO C forbids qualified function types"); + + /* Every function declaration is an external reference + (DECL_EXTERNAL) except for those which are not at file + scope and are explicitly declared "auto". This is + forbidden by standard C (C99 6.7.1p5) and is interpreted by + GCC to signify a forward declaration of a nested function. */ + if (storage_class == csc_auto && current_scope != file_scope) + DECL_EXTERNAL (decl) = 0; + /* In C99, a function which is declared 'inline' with 'extern' + is not an external reference (which is confusing). It + means that the later definition of the function must be output + in this file, C99 6.7.4p6. In GNU C89, a function declared + 'extern inline' is an external reference. */ + else if (declspecs->inline_p && storage_class != csc_static) + DECL_EXTERNAL (decl) = ((storage_class == csc_extern) + == flag_gnu89_inline); + else + DECL_EXTERNAL (decl) = !initialized; + + /* Record absence of global scope for `static' or `auto'. */ + TREE_PUBLIC (decl) + = !(storage_class == csc_static || storage_class == csc_auto); + + /* For a function definition, record the argument information + block where store_parm_decls will look for it. */ + if (funcdef_flag) + current_function_arg_info = arg_info; + + if (declspecs->default_int_p) + C_FUNCTION_IMPLICIT_INT (decl) = 1; + + /* Record presence of `inline' and `_Noreturn', if it is + reasonable. */ + if (flag_hosted && MAIN_NAME_P (declarator->u.id)) + { + if (declspecs->inline_p) + pedwarn (loc, 0, "cannot inline function %<main%>"); + if (declspecs->noreturn_p) + pedwarn (loc, 0, "%<main%> declared %<_Noreturn%>"); + } + else + { + if (declspecs->inline_p) + /* Record that the function is declared `inline'. */ + DECL_DECLARED_INLINE_P (decl) = 1; + if (declspecs->noreturn_p) + { + if (!flag_isoc11) + { + if (flag_isoc99) + pedwarn (loc, OPT_Wpedantic, + "ISO C99 does not support %<_Noreturn%>"); + else + pedwarn (loc, OPT_Wpedantic, + "ISO C90 does not support %<_Noreturn%>"); + } + TREE_THIS_VOLATILE (decl) = 1; + } + } + } + else + { + /* It's a variable. */ + /* An uninitialized decl with `extern' is a reference. */ + int extern_ref = !initialized && storage_class == csc_extern; + + type = c_build_qualified_type (type, type_quals); + + /* C99 6.2.2p7: It is invalid (compile-time undefined + behavior) to create an 'extern' declaration for a + variable if there is a global declaration that is + 'static' and the global declaration is not visible. + (If the static declaration _is_ currently visible, + the 'extern' declaration is taken to refer to that decl.) */ + if (extern_ref && current_scope != file_scope) + { + tree global_decl = identifier_global_value (declarator->u.id); + tree visible_decl = lookup_name (declarator->u.id); + + if (global_decl + && global_decl != visible_decl + && TREE_CODE (global_decl) == VAR_DECL + && !TREE_PUBLIC (global_decl)) + error_at (loc, "variable previously declared %<static%> " + "redeclared %<extern%>"); + } + + decl = build_decl (declarator->id_loc, + VAR_DECL, declarator->u.id, type); + if (size_varies) + C_DECL_VARIABLE_SIZE (decl) = 1; + + if (declspecs->inline_p) + pedwarn (loc, 0, "variable %q+D declared %<inline%>", decl); + if (declspecs->noreturn_p) + pedwarn (loc, 0, "variable %q+D declared %<_Noreturn%>", decl); + + /* At file scope, an initialized extern declaration may follow + a static declaration. In that case, DECL_EXTERNAL will be + reset later in start_decl. */ + DECL_EXTERNAL (decl) = (storage_class == csc_extern); + + /* At file scope, 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 `static' makes it public. */ + if (current_scope == file_scope) + { + TREE_PUBLIC (decl) = storage_class != csc_static; + TREE_STATIC (decl) = !extern_ref; + } + /* Not at file scope, only `static' makes a static definition. */ + else + { + TREE_STATIC (decl) = (storage_class == csc_static); + TREE_PUBLIC (decl) = extern_ref; + } + + if (threadp) + DECL_TLS_MODEL (decl) = decl_default_tls_model (decl); + } + + if ((storage_class == csc_extern + || (storage_class == csc_none + && TREE_CODE (type) == FUNCTION_TYPE + && !funcdef_flag)) + && variably_modified_type_p (type, NULL_TREE)) + { + /* C99 6.7.5.2p2 */ + if (TREE_CODE (type) == FUNCTION_TYPE) + error_at (loc, "non-nested function with variably modified type"); + else + error_at (loc, "object with variably modified type must have " + "no linkage"); + } + + /* Record `register' declaration for warnings on & + and in case doing stupid register allocation. */ + + if (storage_class == csc_register) + { + C_DECL_REGISTER (decl) = 1; + DECL_REGISTER (decl) = 1; + } + + /* Record constancy and volatility. */ + c_apply_type_quals_to_decl (type_quals, decl); + + /* Apply _Alignas specifiers. */ + if (alignas_align) + { + DECL_ALIGN (decl) = alignas_align * BITS_PER_UNIT; + DECL_USER_ALIGN (decl) = 1; + } + + /* 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. + Of course, this only makes sense on VAR,PARM, and RESULT decl's. */ + if (C_TYPE_FIELDS_VOLATILE (TREE_TYPE (decl)) + && (TREE_CODE (decl) == VAR_DECL || TREE_CODE (decl) == PARM_DECL + || TREE_CODE (decl) == RESULT_DECL)) + { + /* It is not an error for a structure with volatile fields to + be declared register, but reset DECL_REGISTER since it + cannot actually go in a register. */ + int was_reg = C_DECL_REGISTER (decl); + C_DECL_REGISTER (decl) = 0; + DECL_REGISTER (decl) = 0; + c_mark_addressable (decl); + C_DECL_REGISTER (decl) = was_reg; + } + + /* This is the earliest point at which we might know the assembler + name of a variable. Thus, if it's known before this, die horribly. */ + gcc_assert (!DECL_ASSEMBLER_NAME_SET_P (decl)); + + if (warn_cxx_compat + && TREE_CODE (decl) == VAR_DECL + && TREE_PUBLIC (decl) + && TREE_STATIC (decl) + && (TREE_CODE (TREE_TYPE (decl)) == RECORD_TYPE + || TREE_CODE (TREE_TYPE (decl)) == UNION_TYPE + || TREE_CODE (TREE_TYPE (decl)) == ENUMERAL_TYPE) + && TYPE_NAME (TREE_TYPE (decl)) == NULL_TREE) + warning_at (DECL_SOURCE_LOCATION (decl), OPT_Wc___compat, + ("non-local variable %qD with anonymous type is " + "questionable in C++"), + decl); + + 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 c-parse.c + 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. + + Return a list of arg types to use in the FUNCTION_TYPE for this function. + + FUNCDEF_FLAG is true for a function definition, false for + a mere declaration. A nonempty identifier-list gets an error message + when FUNCDEF_FLAG is false. */ + +static tree +grokparms (struct c_arg_info *arg_info, bool funcdef_flag) +{ + tree arg_types = arg_info->types; + + if (funcdef_flag && arg_info->had_vla_unspec) + { + /* A function definition isn't function prototype scope C99 6.2.1p4. */ + /* C99 6.7.5.2p4 */ + error ("%<[*]%> not allowed in other than function prototype scope"); + } + + if (arg_types == 0 && !funcdef_flag && !in_system_header) + warning (OPT_Wstrict_prototypes, + "function declaration isn%'t a prototype"); + + if (arg_types == error_mark_node) + return 0; /* don't set TYPE_ARG_TYPES in this case */ + + else if (arg_types && TREE_CODE (TREE_VALUE (arg_types)) == IDENTIFIER_NODE) + { + if (!funcdef_flag) + { + pedwarn (input_location, 0, "parameter names (without types) in function declaration"); + arg_info->parms = NULL_TREE; + } + else + arg_info->parms = arg_info->types; + + arg_info->types = 0; + return 0; + } + else + { + tree parm, type, typelt; + unsigned int parmno; + const char *errmsg; + + /* If there is a parameter of incomplete type in a definition, + this is an error. In a declaration this is valid, and a + struct or union type may be completed later, before any calls + or definition of the function. In the case where the tag was + first declared within the parameter list, a warning has + already been given. If a parameter has void type, then + however the function cannot be defined or called, so + warn. */ + + for (parm = arg_info->parms, typelt = arg_types, parmno = 1; + parm; + parm = DECL_CHAIN (parm), typelt = TREE_CHAIN (typelt), parmno++) + { + type = TREE_VALUE (typelt); + if (type == error_mark_node) + continue; + + if (!COMPLETE_TYPE_P (type)) + { + if (funcdef_flag) + { + if (DECL_NAME (parm)) + error_at (input_location, + "parameter %u (%q+D) has incomplete type", + parmno, parm); + else + error_at (DECL_SOURCE_LOCATION (parm), + "parameter %u has incomplete type", + parmno); + + TREE_VALUE (typelt) = error_mark_node; + TREE_TYPE (parm) = error_mark_node; + arg_types = NULL_TREE; + } + else if (VOID_TYPE_P (type)) + { + if (DECL_NAME (parm)) + warning_at (input_location, 0, + "parameter %u (%q+D) has void type", + parmno, parm); + else + warning_at (DECL_SOURCE_LOCATION (parm), 0, + "parameter %u has void type", + parmno); + } + } + + errmsg = targetm.invalid_parameter_type (type); + if (errmsg) + { + error (errmsg); + TREE_VALUE (typelt) = error_mark_node; + TREE_TYPE (parm) = error_mark_node; + arg_types = NULL_TREE; + } + + if (DECL_NAME (parm) && TREE_USED (parm)) + warn_if_shadowing (parm); + } + return arg_types; + } +} + +/* Allocate and initialize a c_arg_info structure from the parser's + obstack. */ + +struct c_arg_info * +build_arg_info (void) +{ + struct c_arg_info *ret = XOBNEW (&parser_obstack, struct c_arg_info); + ret->parms = NULL_TREE; + ret->tags = NULL; + ret->types = NULL_TREE; + ret->others = NULL_TREE; + ret->pending_sizes = NULL; + ret->had_vla_unspec = 0; + return ret; +} + +/* Take apart the current scope and return a c_arg_info structure with + info on a parameter list just parsed. + + This structure is later fed to 'grokparms' and 'store_parm_decls'. + + ELLIPSIS being true means the argument list ended in '...' so don't + append a sentinel (void_list_node) to the end of the type-list. + + EXPR is NULL or an expression that needs to be evaluated for the + side effects of array size expressions in the parameters. */ + +struct c_arg_info * +get_parm_info (bool ellipsis, tree expr) +{ + struct c_binding *b = current_scope->bindings; + struct c_arg_info *arg_info = build_arg_info (); + + tree parms = 0; + VEC(c_arg_tag,gc) *tags = NULL; + tree types = 0; + tree others = 0; + + static bool explained_incomplete_types = false; + bool gave_void_only_once_err = false; + + arg_info->had_vla_unspec = current_scope->had_vla_unspec; + + /* The bindings in this scope must not get put into a block. + We will take care of deleting the binding nodes. */ + current_scope->bindings = 0; + + /* This function is only called if there was *something* on the + parameter list. */ + gcc_assert (b); + + /* A parameter list consisting solely of 'void' indicates that the + function takes no arguments. But if the 'void' is qualified + (by 'const' or 'volatile'), or has a storage class specifier + ('register'), then the behavior is undefined; issue an error. + Typedefs for 'void' are OK (see DR#157). */ + if (b->prev == 0 /* one binding */ + && TREE_CODE (b->decl) == PARM_DECL /* which is a parameter */ + && !DECL_NAME (b->decl) /* anonymous */ + && VOID_TYPE_P (TREE_TYPE (b->decl))) /* of void type */ + { + if (TREE_THIS_VOLATILE (b->decl) + || TREE_READONLY (b->decl) + || C_DECL_REGISTER (b->decl)) + error ("%<void%> as only parameter may not be qualified"); + + /* There cannot be an ellipsis. */ + if (ellipsis) + error ("%<void%> must be the only parameter"); + + arg_info->types = void_list_node; + return arg_info; + } + + if (!ellipsis) + types = void_list_node; + + /* Break up the bindings list into parms, tags, types, and others; + apply sanity checks; purge the name-to-decl bindings. */ + while (b) + { + tree decl = b->decl; + tree type = TREE_TYPE (decl); + c_arg_tag *tag; + const char *keyword; + + switch (TREE_CODE (decl)) + { + case PARM_DECL: + if (b->id) + { + gcc_assert (I_SYMBOL_BINDING (b->id) == b); + I_SYMBOL_BINDING (b->id) = b->shadowed; + } + + /* Check for forward decls that never got their actual decl. */ + if (TREE_ASM_WRITTEN (decl)) + error ("parameter %q+D has just a forward declaration", decl); + /* Check for (..., void, ...) and issue an error. */ + else if (VOID_TYPE_P (type) && !DECL_NAME (decl)) + { + if (!gave_void_only_once_err) + { + error ("%<void%> must be the only parameter"); + gave_void_only_once_err = true; + } + } + else + { + /* Valid parameter, add it to the list. */ + DECL_CHAIN (decl) = parms; + parms = decl; + + /* Since there is a prototype, args are passed in their + declared types. The back end may override this later. */ + DECL_ARG_TYPE (decl) = type; + types = tree_cons (0, type, types); + } + break; + + case ENUMERAL_TYPE: keyword = "enum"; goto tag; + case UNION_TYPE: keyword = "union"; goto tag; + case RECORD_TYPE: keyword = "struct"; goto tag; + tag: + /* Types may not have tag-names, in which case the type + appears in the bindings list with b->id NULL. */ + if (b->id) + { + gcc_assert (I_TAG_BINDING (b->id) == b); + I_TAG_BINDING (b->id) = b->shadowed; + } + + /* Warn about any struct, union or enum tags defined in a + parameter list. The scope of such types is limited to + the parameter list, which is rarely if ever desirable + (it's impossible to call such a function with type- + correct arguments). An anonymous union parm type is + meaningful as a GNU extension, so don't warn for that. */ + if (TREE_CODE (decl) != UNION_TYPE || b->id != 0) + { + if (b->id) + /* The %s will be one of 'struct', 'union', or 'enum'. */ + warning (0, "%<%s %E%> declared inside parameter list", + keyword, b->id); + else + /* The %s will be one of 'struct', 'union', or 'enum'. */ + warning (0, "anonymous %s declared inside parameter list", + keyword); + + if (!explained_incomplete_types) + { + warning (0, "its scope is only this definition or declaration," + " which is probably not what you want"); + explained_incomplete_types = true; + } + } + + tag = VEC_safe_push (c_arg_tag, gc, tags, NULL); + tag->id = b->id; + tag->type = decl; + break; + + case CONST_DECL: + case TYPE_DECL: + case FUNCTION_DECL: + /* CONST_DECLs appear here when we have an embedded enum, + and TYPE_DECLs appear here when we have an embedded struct + or union. No warnings for this - we already warned about the + type itself. FUNCTION_DECLs appear when there is an implicit + function declaration in the parameter list. */ + + /* When we reinsert this decl in the function body, we need + to reconstruct whether it was marked as nested. */ + gcc_assert (TREE_CODE (decl) == FUNCTION_DECL + ? b->nested + : !b->nested); + DECL_CHAIN (decl) = others; + others = decl; + /* fall through */ + + case ERROR_MARK: + /* error_mark_node appears here when we have an undeclared + variable. Just throw it away. */ + if (b->id) + { + gcc_assert (I_SYMBOL_BINDING (b->id) == b); + I_SYMBOL_BINDING (b->id) = b->shadowed; + } + break; + + /* Other things that might be encountered. */ + case LABEL_DECL: + case VAR_DECL: + default: + gcc_unreachable (); + } + + b = free_binding_and_advance (b); + } + + arg_info->parms = parms; + arg_info->tags = tags; + arg_info->types = types; + arg_info->others = others; + arg_info->pending_sizes = expr; + return arg_info; +} + +/* Get the struct, enum or union (CODE says which) with tag NAME. + Define the tag as a forward-reference with location LOC if it is + not defined. Return a c_typespec structure for the type + specifier. */ + +struct c_typespec +parser_xref_tag (location_t loc, enum tree_code code, tree name) +{ + struct c_typespec ret; + tree ref; + location_t refloc; + + ret.expr = NULL_TREE; + ret.expr_const_operands = true; + + /* If a cross reference is requested, look up the type + already defined for this tag and return it. */ + + ref = lookup_tag (code, name, 0, &refloc); + /* If this is the right type of tag, return what we found. + (This reference will be shadowed by shadow_tag later if appropriate.) + If this is the wrong type of tag, do not return it. If it was the + wrong type in the same scope, we will have had an error + message already; if in a different scope and declaring + a name, pending_xref_error will give an error message; but if in a + different scope and not declaring a name, this tag should + shadow the previous declaration of a different type of tag, and + this would not work properly if we return the reference found. + (For example, with "struct foo" in an outer scope, "union foo;" + must shadow that tag with a new one of union type.) */ + ret.kind = (ref ? ctsk_tagref : ctsk_tagfirstref); + if (ref && TREE_CODE (ref) == code) + { + if (C_TYPE_DEFINED_IN_STRUCT (ref) + && loc != UNKNOWN_LOCATION + && warn_cxx_compat) + { + switch (code) + { + case ENUMERAL_TYPE: + warning_at (loc, OPT_Wc___compat, + ("enum type defined in struct or union " + "is not visible in C++")); + inform (refloc, "enum type defined here"); + break; + case RECORD_TYPE: + warning_at (loc, OPT_Wc___compat, + ("struct defined in struct or union " + "is not visible in C++")); + inform (refloc, "struct defined here"); + break; + case UNION_TYPE: + warning_at (loc, OPT_Wc___compat, + ("union defined in struct or union " + "is not visible in C++")); + inform (refloc, "union defined here"); + break; + default: + gcc_unreachable(); + } + } + + ret.spec = ref; + return ret; + } + + /* 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) + { + /* Give the type a default layout like unsigned int + to avoid crashing if it does not get defined. */ + SET_TYPE_MODE (ref, TYPE_MODE (unsigned_type_node)); + TYPE_ALIGN (ref) = TYPE_ALIGN (unsigned_type_node); + TYPE_USER_ALIGN (ref) = 0; + TYPE_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 (loc, name, ref); + + ret.spec = ref; + return ret; +} + +/* Get the struct, enum or union (CODE says which) with tag NAME. + Define the tag as a forward-reference if it is not defined. + Return a tree for the type. */ + +tree +xref_tag (enum tree_code code, tree name) +{ + return parser_xref_tag (input_location, code, name).spec; +} + +/* Make sure that the tag NAME is defined *in the current scope* + at least as a forward reference. + LOC is the location of the struct's definition. + CODE says which kind of tag NAME ought to be. + + This stores the current value of the file static STRUCT_PARSE_INFO + in *ENCLOSING_STRUCT_PARSE_INFO, and points STRUCT_PARSE_INFO at a + new c_struct_parse_info structure. The old value of + STRUCT_PARSE_INFO is restored in finish_struct. */ + +tree +start_struct (location_t loc, enum tree_code code, tree name, + struct c_struct_parse_info **enclosing_struct_parse_info) +{ + /* If there is already a tag defined at this scope + (as a forward reference), just return it. */ + + tree ref = NULL_TREE; + location_t refloc = UNKNOWN_LOCATION; + + if (name != NULL_TREE) + ref = lookup_tag (code, name, 1, &refloc); + if (ref && TREE_CODE (ref) == code) + { + if (TYPE_SIZE (ref)) + { + if (code == UNION_TYPE) + error_at (loc, "redefinition of %<union %E%>", name); + else + error_at (loc, "redefinition of %<struct %E%>", name); + if (refloc != UNKNOWN_LOCATION) + inform (refloc, "originally defined here"); + /* Don't create structures using a name already in use. */ + ref = NULL_TREE; + } + else if (C_TYPE_BEING_DEFINED (ref)) + { + if (code == UNION_TYPE) + error_at (loc, "nested redefinition of %<union %E%>", name); + else + error_at (loc, "nested redefinition of %<struct %E%>", name); + /* Don't bother to report "originally defined here" for a + nested redefinition; the original definition should be + obvious. */ + /* Don't create structures that contain themselves. */ + ref = NULL_TREE; + } + } + + /* Otherwise create a forward-reference just so the tag is in scope. */ + + if (ref == NULL_TREE || TREE_CODE (ref) != code) + { + ref = make_node (code); + pushtag (loc, name, ref); + } + + C_TYPE_BEING_DEFINED (ref) = 1; + TYPE_PACKED (ref) = flag_pack_struct; + + *enclosing_struct_parse_info = struct_parse_info; + struct_parse_info = XNEW (struct c_struct_parse_info); + struct_parse_info->struct_types = VEC_alloc (tree, heap, 0); + struct_parse_info->fields = VEC_alloc (c_binding_ptr, heap, 0); + struct_parse_info->typedefs_seen = VEC_alloc (tree, heap, 0); + + /* FIXME: This will issue a warning for a use of a type defined + within a statement expr used within sizeof, et. al. This is not + terribly serious as C++ doesn't permit statement exprs within + sizeof anyhow. */ + if (warn_cxx_compat && (in_sizeof || in_typeof || in_alignof)) + warning_at (loc, OPT_Wc___compat, + "defining type in %qs expression is invalid in C++", + (in_sizeof + ? "sizeof" + : (in_typeof ? "typeof" : "alignof"))); + + return ref; +} + +/* Process the specs, declarator 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. + DECL_ATTRS is as for grokdeclarator. + + LOC is the location of the structure component. + + 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 (location_t loc, + struct c_declarator *declarator, struct c_declspecs *declspecs, + tree width, tree *decl_attrs) +{ + tree value; + + if (declarator->kind == cdk_id && declarator->u.id == NULL_TREE + && width == NULL_TREE) + { + /* This is an unnamed decl. + + If we have something of the form "union { list } ;" then this + is the anonymous union extension. Similarly for struct. + + If this is something of the form "struct foo;", then + If MS or Plan 9 extensions are enabled, this is handled as + an anonymous struct. + Otherwise this is a forward declaration of a structure tag. + + If this is something of the form "foo;" and foo is a TYPE_DECL, then + If foo names a structure or union without a tag, then this + is an anonymous struct (this is permitted by C11). + If MS or Plan 9 extensions are enabled and foo names a + structure, then again this is an anonymous struct. + Otherwise this is an error. + + Oh what a horrid tangled web we weave. I wonder if MS consciously + took this from Plan 9 or if it was an accident of implementation + that took root before someone noticed the bug... */ + + tree type = declspecs->type; + bool type_ok = (TREE_CODE (type) == RECORD_TYPE + || TREE_CODE (type) == UNION_TYPE); + bool ok = false; + + if (type_ok + && (flag_ms_extensions + || flag_plan9_extensions + || !declspecs->typedef_p)) + { + if (flag_ms_extensions || flag_plan9_extensions) + ok = true; + else if (TYPE_NAME (type) == NULL) + ok = true; + else + ok = false; + } + if (!ok) + { + pedwarn (loc, 0, "declaration does not declare anything"); + return NULL_TREE; + } + if (!flag_isoc11) + { + if (flag_isoc99) + pedwarn (loc, OPT_Wpedantic, + "ISO C99 doesn%'t support unnamed structs/unions"); + else + pedwarn (loc, OPT_Wpedantic, + "ISO C90 doesn%'t support unnamed structs/unions"); + } + } + + value = grokdeclarator (declarator, declspecs, FIELD, false, + width ? &width : NULL, decl_attrs, NULL, NULL, + DEPRECATED_NORMAL); + + finish_decl (value, loc, NULL_TREE, NULL_TREE, NULL_TREE); + DECL_INITIAL (value) = width; + + if (warn_cxx_compat && DECL_NAME (value) != NULL_TREE) + { + /* If we currently have a binding for this field, set the + in_struct field in the binding, so that we warn about lookups + which find it. */ + struct c_binding *b = I_SYMBOL_BINDING (DECL_NAME (value)); + if (b != NULL) + { + /* If the in_struct field is not yet set, push it on a list + to be cleared when this struct is finished. */ + if (!b->in_struct) + { + VEC_safe_push (c_binding_ptr, heap, + struct_parse_info->fields, b); + b->in_struct = 1; + } + } + } + + return value; +} + +/* Subroutine of detect_field_duplicates: return whether X and Y, + which are both fields in the same struct, have duplicate field + names. */ + +static bool +is_duplicate_field (tree x, tree y) +{ + if (DECL_NAME (x) != NULL_TREE && DECL_NAME (x) == DECL_NAME (y)) + return true; + + /* When using -fplan9-extensions, an anonymous field whose name is a + typedef can duplicate a field name. */ + if (flag_plan9_extensions + && (DECL_NAME (x) == NULL_TREE || DECL_NAME (y) == NULL_TREE)) + { + tree xt, xn, yt, yn; + + xt = TREE_TYPE (x); + if (DECL_NAME (x) != NULL_TREE) + xn = DECL_NAME (x); + else if ((TREE_CODE (xt) == RECORD_TYPE || TREE_CODE (xt) == UNION_TYPE) + && TYPE_NAME (xt) != NULL_TREE + && TREE_CODE (TYPE_NAME (xt)) == TYPE_DECL) + xn = DECL_NAME (TYPE_NAME (xt)); + else + xn = NULL_TREE; + + yt = TREE_TYPE (y); + if (DECL_NAME (y) != NULL_TREE) + yn = DECL_NAME (y); + else if ((TREE_CODE (yt) == RECORD_TYPE || TREE_CODE (yt) == UNION_TYPE) + && TYPE_NAME (yt) != NULL_TREE + && TREE_CODE (TYPE_NAME (yt)) == TYPE_DECL) + yn = DECL_NAME (TYPE_NAME (yt)); + else + yn = NULL_TREE; + + if (xn != NULL_TREE && xn == yn) + return true; + } + + return false; +} + +/* Subroutine of detect_field_duplicates: add the fields of FIELDLIST + to HTAB, giving errors for any duplicates. */ + +static void +detect_field_duplicates_hash (tree fieldlist, htab_t htab) +{ + tree x, y; + void **slot; + + for (x = fieldlist; x ; x = DECL_CHAIN (x)) + if ((y = DECL_NAME (x)) != 0) + { + slot = htab_find_slot (htab, y, INSERT); + if (*slot) + { + error ("duplicate member %q+D", x); + DECL_NAME (x) = NULL_TREE; + } + *slot = y; + } + else if (TREE_CODE (TREE_TYPE (x)) == RECORD_TYPE + || TREE_CODE (TREE_TYPE (x)) == UNION_TYPE) + { + detect_field_duplicates_hash (TYPE_FIELDS (TREE_TYPE (x)), htab); + + /* When using -fplan9-extensions, an anonymous field whose + name is a typedef can duplicate a field name. */ + if (flag_plan9_extensions + && TYPE_NAME (TREE_TYPE (x)) != NULL_TREE + && TREE_CODE (TYPE_NAME (TREE_TYPE (x))) == TYPE_DECL) + { + tree xn = DECL_NAME (TYPE_NAME (TREE_TYPE (x))); + slot = htab_find_slot (htab, xn, INSERT); + if (*slot) + error ("duplicate member %q+D", TYPE_NAME (TREE_TYPE (x))); + *slot = xn; + } + } +} + +/* Generate an error for any duplicate field names in FIELDLIST. Munge + the list such that this does not present a problem later. */ + +static void +detect_field_duplicates (tree fieldlist) +{ + tree x, y; + int timeout = 10; + + /* If the struct is the list of instance variables of an Objective-C + class, then we need to check all the instance variables of + superclasses when checking for duplicates (since you can't have + an instance variable in a subclass with the same name as an + instance variable in a superclass). We pass on this job to the + Objective-C compiler. objc_detect_field_duplicates() will return + false if we are not checking the list of instance variables and + the C frontend should proceed with the standard field duplicate + checks. If we are checking the list of instance variables, the + ObjC frontend will do the check, emit the errors if needed, and + then return true. */ + if (c_dialect_objc ()) + if (objc_detect_field_duplicates (false)) + return; + + /* First, see if there are more than "a few" fields. + This is trivially true if there are zero or one fields. */ + if (!fieldlist || !DECL_CHAIN (fieldlist)) + return; + x = fieldlist; + do { + timeout--; + if (DECL_NAME (x) == NULL_TREE + && (TREE_CODE (TREE_TYPE (x)) == RECORD_TYPE + || TREE_CODE (TREE_TYPE (x)) == UNION_TYPE)) + timeout = 0; + x = DECL_CHAIN (x); + } while (timeout > 0 && x); + + /* If there were "few" fields and no anonymous structures or unions, + avoid the overhead of allocating a hash table. Instead just do + the nested traversal thing. */ + if (timeout > 0) + { + for (x = DECL_CHAIN (fieldlist); x; x = DECL_CHAIN (x)) + /* When using -fplan9-extensions, we can have duplicates + between typedef names and fields. */ + if (DECL_NAME (x) + || (flag_plan9_extensions + && DECL_NAME (x) == NULL_TREE + && (TREE_CODE (TREE_TYPE (x)) == RECORD_TYPE + || TREE_CODE (TREE_TYPE (x)) == UNION_TYPE) + && TYPE_NAME (TREE_TYPE (x)) != NULL_TREE + && TREE_CODE (TYPE_NAME (TREE_TYPE (x))) == TYPE_DECL)) + { + for (y = fieldlist; y != x; y = TREE_CHAIN (y)) + if (is_duplicate_field (y, x)) + { + error ("duplicate member %q+D", x); + DECL_NAME (x) = NULL_TREE; + } + } + } + else + { + htab_t htab = htab_create (37, htab_hash_pointer, htab_eq_pointer, NULL); + + detect_field_duplicates_hash (fieldlist, htab); + htab_delete (htab); + } +} + +/* Finish up struct info used by -Wc++-compat. */ + +static void +warn_cxx_compat_finish_struct (tree fieldlist) +{ + unsigned int ix; + tree x; + struct c_binding *b; + + /* Set the C_TYPE_DEFINED_IN_STRUCT flag for each type defined in + the current struct. We do this now at the end of the struct + because the flag is used to issue visibility warnings, and we + only want to issue those warnings if the type is referenced + outside of the struct declaration. */ + FOR_EACH_VEC_ELT (tree, struct_parse_info->struct_types, ix, x) + C_TYPE_DEFINED_IN_STRUCT (x) = 1; + + /* The TYPEDEFS_SEEN field of STRUCT_PARSE_INFO is a list of + typedefs used when declaring fields in this struct. If the name + of any of the fields is also a typedef name then the struct would + not parse in C++, because the C++ lookup rules say that the + typedef name would be looked up in the context of the struct, and + would thus be the field rather than the typedef. */ + if (!VEC_empty (tree, struct_parse_info->typedefs_seen) + && fieldlist != NULL_TREE) + { + /* Use a pointer_set using the name of the typedef. We can use + a pointer_set because identifiers are interned. */ + struct pointer_set_t *tset = pointer_set_create (); + + FOR_EACH_VEC_ELT (tree, struct_parse_info->typedefs_seen, ix, x) + pointer_set_insert (tset, DECL_NAME (x)); + + for (x = fieldlist; x != NULL_TREE; x = DECL_CHAIN (x)) + { + if (DECL_NAME (x) != NULL_TREE + && pointer_set_contains (tset, DECL_NAME (x))) + { + warning_at (DECL_SOURCE_LOCATION (x), OPT_Wc___compat, + ("using %qD as both field and typedef name is " + "invalid in C++"), + x); + /* FIXME: It would be nice to report the location where + the typedef name is used. */ + } + } + + pointer_set_destroy (tset); + } + + /* For each field which has a binding and which was not defined in + an enclosing struct, clear the in_struct field. */ + FOR_EACH_VEC_ELT (c_binding_ptr, struct_parse_info->fields, ix, b) + b->in_struct = 0; +} + +/* Fill in the fields of a RECORD_TYPE or UNION_TYPE node, T. + LOC is the location of the RECORD_TYPE or UNION_TYPE's definition. + FIELDLIST is a chain of FIELD_DECL nodes for the fields. + ATTRIBUTES are attributes to be applied to the structure. + + ENCLOSING_STRUCT_PARSE_INFO is the value of STRUCT_PARSE_INFO when + the struct was started. */ + +tree +finish_struct (location_t loc, tree t, tree fieldlist, tree attributes, + struct c_struct_parse_info *enclosing_struct_parse_info) +{ + tree x; + bool toplevel = file_scope == current_scope; + int saw_named_field; + + /* 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, (int) ATTR_FLAG_TYPE_IN_PLACE); + + if (pedantic) + { + for (x = fieldlist; x; x = DECL_CHAIN (x)) + { + if (DECL_NAME (x) != 0) + break; + if (flag_isoc11 + && (TREE_CODE (TREE_TYPE (x)) == RECORD_TYPE + || TREE_CODE (TREE_TYPE (x)) == UNION_TYPE)) + break; + } + + if (x == 0) + { + if (TREE_CODE (t) == UNION_TYPE) + { + if (fieldlist) + pedwarn (loc, OPT_Wpedantic, "union has no named members"); + else + pedwarn (loc, OPT_Wpedantic, "union has no members"); + } + else + { + if (fieldlist) + pedwarn (loc, OPT_Wpedantic, "struct has no named members"); + else + pedwarn (loc, OPT_Wpedantic, "struct has no members"); + } + } + } + + /* Install struct as DECL_CONTEXT of each field decl. + Also process specified field sizes, found in the DECL_INITIAL, + storing 0 there after the type has been changed to precision equal + to its width, rather than the precision of the specified standard + type. (Correct layout requires the original type to have been preserved + until now.) */ + + saw_named_field = 0; + for (x = fieldlist; x; x = DECL_CHAIN (x)) + { + if (TREE_TYPE (x) == error_mark_node) + continue; + + DECL_CONTEXT (x) = t; + + /* 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 = strip_array_types (TREE_TYPE (x)); + 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; + + if (DECL_INITIAL (x)) + { + unsigned HOST_WIDE_INT width = tree_low_cst (DECL_INITIAL (x), 1); + DECL_SIZE (x) = bitsize_int (width); + DECL_BIT_FIELD (x) = 1; + SET_DECL_C_BIT_FIELD (x); + } + + if (TYPE_PACKED (t) + && (DECL_BIT_FIELD (x) + || TYPE_ALIGN (TREE_TYPE (x)) > BITS_PER_UNIT)) + DECL_PACKED (x) = 1; + + /* Detect flexible array member in an invalid context. */ + if (TREE_CODE (TREE_TYPE (x)) == ARRAY_TYPE + && TYPE_SIZE (TREE_TYPE (x)) == NULL_TREE + && TYPE_DOMAIN (TREE_TYPE (x)) != NULL_TREE + && TYPE_MAX_VALUE (TYPE_DOMAIN (TREE_TYPE (x))) == NULL_TREE) + { + if (TREE_CODE (t) == UNION_TYPE) + { + error_at (DECL_SOURCE_LOCATION (x), + "flexible array member in union"); + TREE_TYPE (x) = error_mark_node; + } + else if (DECL_CHAIN (x) != NULL_TREE) + { + error_at (DECL_SOURCE_LOCATION (x), + "flexible array member not at end of struct"); + TREE_TYPE (x) = error_mark_node; + } + else if (!saw_named_field) + { + error_at (DECL_SOURCE_LOCATION (x), + "flexible array member in otherwise empty struct"); + TREE_TYPE (x) = error_mark_node; + } + } + + if (pedantic && TREE_CODE (t) == RECORD_TYPE + && flexible_array_type_p (TREE_TYPE (x))) + pedwarn (DECL_SOURCE_LOCATION (x), OPT_Wpedantic, + "invalid use of structure with flexible array member"); + + if (DECL_NAME (x) + || TREE_CODE (TREE_TYPE (x)) == RECORD_TYPE + || TREE_CODE (TREE_TYPE (x)) == UNION_TYPE) + saw_named_field = 1; + } + + detect_field_duplicates (fieldlist); + + /* 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); + + /* Give bit-fields their proper types. */ + { + tree *fieldlistp = &fieldlist; + while (*fieldlistp) + if (TREE_CODE (*fieldlistp) == FIELD_DECL && DECL_INITIAL (*fieldlistp) + && TREE_TYPE (*fieldlistp) != error_mark_node) + { + unsigned HOST_WIDE_INT width + = tree_low_cst (DECL_INITIAL (*fieldlistp), 1); + tree type = TREE_TYPE (*fieldlistp); + if (width != TYPE_PRECISION (type)) + { + TREE_TYPE (*fieldlistp) + = c_build_bitfield_integer_type (width, TYPE_UNSIGNED (type)); + DECL_MODE (*fieldlistp) = TYPE_MODE (TREE_TYPE (*fieldlistp)); + } + DECL_INITIAL (*fieldlistp) = 0; + } + else + fieldlistp = &DECL_CHAIN (*fieldlistp); + } + + /* 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 = DECL_CHAIN (x)) + { + if (len > 15 || DECL_NAME (x) == NULL) + break; + len += 1; + } + + if (len > 15) + { + tree *field_array; + struct lang_type *space; + struct sorted_fields_type *space2; + + 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. */ + + space = ggc_alloc_cleared_lang_type (sizeof (struct lang_type)); + space2 = ggc_alloc_sorted_fields_type + (sizeof (struct sorted_fields_type) + len * sizeof (tree)); + + len = 0; + space->s = space2; + field_array = &space2->elts[0]; + for (x = fieldlist; x; x = DECL_CHAIN (x)) + { + field_array[len++] = x; + + /* If there is anonymous struct or union, break out of the loop. */ + if (DECL_NAME (x) == NULL) + break; + } + /* Found no anonymous struct/union. Add the TYPE_LANG_SPECIFIC. */ + if (x == NULL) + { + TYPE_LANG_SPECIFIC (t) = space; + TYPE_LANG_SPECIFIC (t)->s->len = len; + field_array = TYPE_LANG_SPECIFIC (t)->s->elts; + 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); + C_TYPE_FIELDS_READONLY (x) = C_TYPE_FIELDS_READONLY (t); + C_TYPE_FIELDS_VOLATILE (x) = C_TYPE_FIELDS_VOLATILE (t); + C_TYPE_VARIABLE_SIZE (x) = C_TYPE_VARIABLE_SIZE (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_AGGR (t) + && (!TYPE_FIELDS (t) || TYPE_MODE (t) != DECL_MODE (TYPE_FIELDS (t)))) + { + TYPE_TRANSPARENT_AGGR (t) = 0; + warning_at (loc, 0, "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. */ + for (x = C_TYPE_INCOMPLETE_VARS (TYPE_MAIN_VARIANT (t)); + x; + x = TREE_CHAIN (x)) + { + tree decl = TREE_VALUE (x); + if (TREE_CODE (TREE_TYPE (decl)) == ARRAY_TYPE) + layout_array_type (TREE_TYPE (decl)); + if (TREE_CODE (decl) != TYPE_DECL) + { + layout_decl (decl, 0); + if (c_dialect_objc ()) + objc_check_decl (decl); + rest_of_decl_compilation (decl, toplevel, 0); + } + } + C_TYPE_INCOMPLETE_VARS (TYPE_MAIN_VARIANT (t)) = 0; + + /* Update type location to the one of the definition, instead of e.g. + a forward declaration. */ + if (TYPE_STUB_DECL (t)) + DECL_SOURCE_LOCATION (TYPE_STUB_DECL (t)) = loc; + + /* Finish debugging output for this type. */ + rest_of_type_compilation (t, toplevel); + + /* If we're inside a function proper, i.e. not file-scope and not still + parsing parameters, then arrange for the size of a variable sized type + to be bound now. */ + if (building_stmt_list_p () && variably_modified_type_p (t, NULL_TREE)) + add_stmt (build_stmt (loc, + DECL_EXPR, build_decl (loc, TYPE_DECL, NULL, t))); + + if (warn_cxx_compat) + warn_cxx_compat_finish_struct (fieldlist); + + VEC_free (tree, heap, struct_parse_info->struct_types); + VEC_free (c_binding_ptr, heap, struct_parse_info->fields); + VEC_free (tree, heap, struct_parse_info->typedefs_seen); + XDELETE (struct_parse_info); + + struct_parse_info = enclosing_struct_parse_info; + + /* If this struct is defined inside a struct, add it to + struct_types. */ + if (warn_cxx_compat + && struct_parse_info != NULL + && !in_sizeof && !in_typeof && !in_alignof) + VEC_safe_push (tree, heap, struct_parse_info->struct_types, t); + + return t; +} + +/* Lay out the type T, and its element type, and so on. */ + +static void +layout_array_type (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). + LOC is the enum's location. + 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 (location_t loc, struct c_enum_contents *the_enum, tree name) +{ + tree enumtype = NULL_TREE; + location_t enumloc = UNKNOWN_LOCATION; + + /* 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 != NULL_TREE) + enumtype = lookup_tag (ENUMERAL_TYPE, name, 1, &enumloc); + + if (enumtype == 0 || TREE_CODE (enumtype) != ENUMERAL_TYPE) + { + enumtype = make_node (ENUMERAL_TYPE); + pushtag (loc, name, enumtype); + } + + if (C_TYPE_BEING_DEFINED (enumtype)) + error_at (loc, "nested redefinition of %<enum %E%>", name); + + C_TYPE_BEING_DEFINED (enumtype) = 1; + + if (TYPE_VALUES (enumtype) != 0) + { + /* This enum is a named one that has been declared already. */ + error_at (loc, "redeclaration of %<enum %E%>", name); + if (enumloc != UNKNOWN_LOCATION) + inform (enumloc, "originally defined here"); + + /* Completely replace its old definition. + The old enumerators remain defined, however. */ + TYPE_VALUES (enumtype) = 0; + } + + the_enum->enum_next_value = integer_zero_node; + the_enum->enum_overflow = 0; + + if (flag_short_enums) + TYPE_PACKED (enumtype) = 1; + + /* FIXME: This will issue a warning for a use of a type defined + within sizeof in a statement expr. This is not terribly serious + as C++ doesn't permit statement exprs within sizeof anyhow. */ + if (warn_cxx_compat && (in_sizeof || in_typeof || in_alignof)) + warning_at (loc, OPT_Wc___compat, + "defining type in %qs expression is invalid in C++", + (in_sizeof + ? "sizeof" + : (in_typeof ? "typeof" : "alignof"))); + + 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 (tree enumtype, tree values, tree attributes) +{ + tree pair, tem; + tree minnode = 0, maxnode = 0; + int precision, unsign; + bool toplevel = (file_scope == current_scope); + struct lang_type *lt; + + decl_attributes (&enumtype, attributes, (int) ATTR_FLAG_TYPE_IN_PLACE); + + /* Calculate the maximum value of any enumerator in this type. */ + + if (values == error_mark_node) + minnode = maxnode = integer_zero_node; + else + { + minnode = maxnode = TREE_VALUE (values); + for (pair = TREE_CHAIN (values); pair; pair = TREE_CHAIN (pair)) + { + tree value = TREE_VALUE (pair); + if (tree_int_cst_lt (maxnode, value)) + maxnode = value; + if (tree_int_cst_lt (value, minnode)) + minnode = value; + } + } + + /* Construct the final type of this enumeration. It is the same + as one of the integral types - the narrowest one that fits, except + that normally we only go as narrow as int - and signed iff any of + the values are negative. */ + unsign = (tree_int_cst_sgn (minnode) >= 0); + precision = MAX (tree_int_cst_min_precision (minnode, unsign), + tree_int_cst_min_precision (maxnode, unsign)); + + if (TYPE_PACKED (enumtype) || precision > TYPE_PRECISION (integer_type_node)) + { + tem = c_common_type_for_size (precision, unsign); + if (tem == NULL) + { + warning (0, "enumeration values exceed range of largest integer"); + tem = long_long_integer_type_node; + } + } + else + tem = unsign ? unsigned_type_node : integer_type_node; + + TYPE_MIN_VALUE (enumtype) = TYPE_MIN_VALUE (tem); + TYPE_MAX_VALUE (enumtype) = TYPE_MAX_VALUE (tem); + TYPE_UNSIGNED (enumtype) = TYPE_UNSIGNED (tem); + TYPE_SIZE (enumtype) = 0; + + /* If the precision of the type was specific with an attribute and it + was too small, give an error. Otherwise, use it. */ + if (TYPE_PRECISION (enumtype)) + { + if (precision > TYPE_PRECISION (enumtype)) + error ("specified mode too small for enumeral values"); + } + else + TYPE_PRECISION (enumtype) = TYPE_PRECISION (tem); + + layout_type (enumtype); + + if (values != error_mark_node) + { + /* Change the type of the enumerators to be the enum type. We + need to do this irrespective of the size of the enum, for + proper type checking. Replace the DECL_INITIALs of the + enumerators, and the value slots of the list, with copies + that have the enum type; they cannot be modified in place + because they may be shared (e.g. integer_zero_node) Finally, + change the purpose slots to point to the names of the decls. */ + for (pair = values; pair; pair = TREE_CHAIN (pair)) + { + tree enu = TREE_PURPOSE (pair); + tree ini = DECL_INITIAL (enu); + + TREE_TYPE (enu) = enumtype; + + /* The ISO C Standard mandates enumerators to have type int, + even though the underlying type of an enum type is + unspecified. However, GCC allows enumerators of any + integer type as an extensions. build_enumerator() + converts any enumerators that fit in an int to type int, + to avoid promotions to unsigned types when comparing + integers with enumerators that fit in the int range. + When -pedantic is given, build_enumerator() would have + already warned about those that don't fit. Here we + convert the rest to the enumerator type. */ + if (TREE_TYPE (ini) != integer_type_node) + ini = convert (enumtype, ini); + + DECL_INITIAL (enu) = ini; + TREE_PURPOSE (pair) = DECL_NAME (enu); + TREE_VALUE (pair) = ini; + } + + TYPE_VALUES (enumtype) = values; + } + + /* Record the min/max values so that we can warn about bit-field + enumerations that are too small for the values. */ + lt = ggc_alloc_cleared_lang_type (sizeof (struct lang_type)); + lt->enum_min = minnode; + lt->enum_max = maxnode; + TYPE_LANG_SPECIFIC (enumtype) = lt; + + /* Fix up all variant types of this enum type. */ + for (tem = TYPE_MAIN_VARIANT (enumtype); tem; tem = TYPE_NEXT_VARIANT (tem)) + { + if (tem == enumtype) + continue; + 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); + SET_TYPE_MODE (tem, TYPE_MODE (enumtype)); + TYPE_PRECISION (tem) = TYPE_PRECISION (enumtype); + TYPE_ALIGN (tem) = TYPE_ALIGN (enumtype); + TYPE_USER_ALIGN (tem) = TYPE_USER_ALIGN (enumtype); + TYPE_UNSIGNED (tem) = TYPE_UNSIGNED (enumtype); + TYPE_LANG_SPECIFIC (tem) = TYPE_LANG_SPECIFIC (enumtype); + } + + /* Finish debugging output for this type. */ + rest_of_type_compilation (enumtype, toplevel); + + /* If this enum is defined inside a struct, add it to + struct_types. */ + if (warn_cxx_compat + && struct_parse_info != NULL + && !in_sizeof && !in_typeof && !in_alignof) + VEC_safe_push (tree, heap, struct_parse_info->struct_types, enumtype); + + return enumtype; +} + +/* Build and install a CONST_DECL for one value of the + current enumeration type (one that was begun with start_enum). + DECL_LOC is the location of the enumerator. + LOC is the location of the '=' operator if any, DECL_LOC otherwise. + Return a tree-list containing the CONST_DECL and its value. + Assignment of sequential values by default is handled here. */ + +tree +build_enumerator (location_t decl_loc, location_t loc, + struct c_enum_contents *the_enum, tree name, tree value) +{ + tree decl, type; + + /* Validate and default VALUE. */ + + if (value != 0) + { + /* Don't issue more errors for error_mark_node (i.e. an + undeclared identifier) - just ignore the value expression. */ + if (value == error_mark_node) + value = 0; + else if (!INTEGRAL_TYPE_P (TREE_TYPE (value))) + { + error_at (loc, "enumerator value for %qE is not an integer constant", + name); + value = 0; + } + else + { + if (TREE_CODE (value) != INTEGER_CST) + { + value = c_fully_fold (value, false, NULL); + if (TREE_CODE (value) == INTEGER_CST) + pedwarn (loc, OPT_Wpedantic, + "enumerator value for %qE is not an integer " + "constant expression", name); + } + if (TREE_CODE (value) != INTEGER_CST) + { + error ("enumerator value for %qE is not an integer constant", + name); + value = 0; + } + else + { + value = default_conversion (value); + constant_expression_warning (value); + } + } + } + + /* Default based on previous value. */ + /* It should no longer be possible to have NON_LVALUE_EXPR + in the default. */ + if (value == 0) + { + value = the_enum->enum_next_value; + if (the_enum->enum_overflow) + error_at (loc, "overflow in enumeration values"); + } + /* Even though the underlying type of an enum is unspecified, the + type of enumeration constants is explicitly defined as int + (6.4.4.3/2 in the C99 Standard). GCC allows any integer type as + an extension. */ + else if (!int_fits_type_p (value, integer_type_node)) + pedwarn (loc, OPT_Wpedantic, + "ISO C restricts enumerator values to range of %<int%>"); + + /* The ISO C Standard mandates enumerators to have type int, even + though the underlying type of an enum type is unspecified. + However, GCC allows enumerators of any integer type as an + extensions. Here we convert any enumerators that fit in an int + to type int, to avoid promotions to unsigned types when comparing + integers with enumerators that fit in the int range. When + -pedantic is given, we would have already warned about those that + don't fit. We have to do this here rather than in finish_enum + because this value may be used to define more enumerators. */ + if (int_fits_type_p (value, integer_type_node)) + value = convert (integer_type_node, value); + + /* Set basis for default for next value. */ + the_enum->enum_next_value + = build_binary_op (EXPR_LOC_OR_HERE (value), + PLUS_EXPR, value, integer_one_node, 0); + the_enum->enum_overflow = tree_int_cst_lt (the_enum->enum_next_value, value); + + /* Now create a declaration for the enum value name. */ + + type = TREE_TYPE (value); + type = c_common_type_for_size (MAX (TYPE_PRECISION (type), + TYPE_PRECISION (integer_type_node)), + (TYPE_PRECISION (type) + >= TYPE_PRECISION (integer_type_node) + && TYPE_UNSIGNED (type))); + + decl = build_decl (decl_loc, CONST_DECL, name, type); + DECL_INITIAL (decl) = convert (type, value); + pushdecl (decl); + + return tree_cons (decl, value, NULL_TREE); +} + + +/* Create the FUNCTION_DECL for a function definition. + DECLSPECS, DECLARATOR 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. */ + +int +start_function (struct c_declspecs *declspecs, struct c_declarator *declarator, + tree attributes) +{ + tree decl1, old_decl; + tree restype, resdecl; + location_t loc; + + current_function_returns_value = 0; /* Assume, until we see it does. */ + current_function_returns_null = 0; + current_function_returns_abnormally = 0; + warn_about_return_type = 0; + c_switch_stack = NULL; + + /* Indicate no valid break/continue context by setting these variables + to some non-null, non-label value. We'll notice and emit the proper + error message in c_finish_bc_stmt. */ + c_break_label = c_cont_label = size_zero_node; + + decl1 = grokdeclarator (declarator, declspecs, FUNCDEF, true, NULL, + &attributes, NULL, NULL, DEPRECATED_NORMAL); + + /* If the declarator is not suitable for a function definition, + cause a syntax error. */ + if (decl1 == 0 + || TREE_CODE (decl1) != FUNCTION_DECL) + return 0; + + loc = DECL_SOURCE_LOCATION (decl1); + + decl_attributes (&decl1, attributes, 0); + + if (DECL_DECLARED_INLINE_P (decl1) + && DECL_UNINLINABLE (decl1) + && lookup_attribute ("noinline", DECL_ATTRIBUTES (decl1))) + warning_at (loc, OPT_Wattributes, + "inline function %qD given attribute noinline", + decl1); + + /* Handle gnu_inline attribute. */ + if (declspecs->inline_p + && !flag_gnu89_inline + && TREE_CODE (decl1) == FUNCTION_DECL + && (lookup_attribute ("gnu_inline", DECL_ATTRIBUTES (decl1)) + || current_function_decl)) + { + if (declspecs->storage_class != csc_static) + DECL_EXTERNAL (decl1) = !DECL_EXTERNAL (decl1); + } + + announce_function (decl1); + + if (!COMPLETE_OR_VOID_TYPE_P (TREE_TYPE (TREE_TYPE (decl1)))) + { + error_at (loc, "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) + pedwarn_c99 (loc, flag_isoc99 ? 0 + : (warn_return_type ? OPT_Wreturn_type : OPT_Wimplicit_int), + "return type defaults to %<int%>"); + + /* Make the init_value nonzero so pushdecl knows this is not tentative. + error_mark_node is replaced below (in pop_scope) with the BLOCK. */ + DECL_INITIAL (decl1) = error_mark_node; + + /* A nested function is not global. */ + if (current_function_decl != 0) + TREE_PUBLIC (decl1) = 0; + + /* If this definition isn't a prototype and we had a prototype declaration + before, copy the arg type info from that prototype. */ + old_decl = lookup_name_in_scope (DECL_NAME (decl1), current_scope); + if (old_decl && TREE_CODE (old_decl) != FUNCTION_DECL) + old_decl = 0; + current_function_prototype_locus = UNKNOWN_LOCATION; + current_function_prototype_built_in = false; + current_function_prototype_arg_types = NULL_TREE; + if (!prototype_p (TREE_TYPE (decl1))) + { + if (old_decl != 0 && TREE_CODE (TREE_TYPE (old_decl)) == FUNCTION_TYPE + && comptypes (TREE_TYPE (TREE_TYPE (decl1)), + TREE_TYPE (TREE_TYPE (old_decl)))) + { + TREE_TYPE (decl1) = composite_type (TREE_TYPE (old_decl), + TREE_TYPE (decl1)); + current_function_prototype_locus = DECL_SOURCE_LOCATION (old_decl); + current_function_prototype_built_in + = C_DECL_BUILTIN_PROTOTYPE (old_decl); + current_function_prototype_arg_types + = TYPE_ARG_TYPES (TREE_TYPE (decl1)); + } + if (TREE_PUBLIC (decl1)) + { + /* If there is an external prototype declaration of this + function, record its location but do not copy information + to this decl. This may be an invisible declaration + (built-in or in a scope which has finished) or simply + have more refined argument types than any declaration + found above. */ + struct c_binding *b; + for (b = I_SYMBOL_BINDING (DECL_NAME (decl1)); b; b = b->shadowed) + if (B_IN_SCOPE (b, external_scope)) + break; + if (b) + { + tree ext_decl, ext_type; + ext_decl = b->decl; + ext_type = b->u.type ? b->u.type : TREE_TYPE (ext_decl); + if (TREE_CODE (ext_type) == FUNCTION_TYPE + && comptypes (TREE_TYPE (TREE_TYPE (decl1)), + TREE_TYPE (ext_type))) + { + current_function_prototype_locus + = DECL_SOURCE_LOCATION (ext_decl); + current_function_prototype_built_in + = C_DECL_BUILTIN_PROTOTYPE (ext_decl); + current_function_prototype_arg_types + = TYPE_ARG_TYPES (ext_type); + } + } + } + } + + /* Optionally warn of old-fashioned def with no previous prototype. */ + if (warn_strict_prototypes + && old_decl != error_mark_node + && !prototype_p (TREE_TYPE (decl1)) + && C_DECL_ISNT_PROTOTYPE (old_decl)) + warning_at (loc, OPT_Wstrict_prototypes, + "function declaration isn%'t a prototype"); + /* Optionally warn of any global def with no previous prototype. */ + else if (warn_missing_prototypes + && old_decl != error_mark_node + && TREE_PUBLIC (decl1) + && !MAIN_NAME_P (DECL_NAME (decl1)) + && C_DECL_ISNT_PROTOTYPE (old_decl)) + warning_at (loc, OPT_Wmissing_prototypes, + "no previous prototype for %qD", decl1); + /* Optionally warn of any def with no previous prototype + if the function has already been used. */ + else if (warn_missing_prototypes + && old_decl != 0 + && old_decl != error_mark_node + && TREE_USED (old_decl) + && !prototype_p (TREE_TYPE (old_decl))) + warning_at (loc, OPT_Wmissing_prototypes, + "%qD was used with no prototype before its definition", decl1); + /* Optionally warn of any global def with no previous declaration. */ + else if (warn_missing_declarations + && TREE_PUBLIC (decl1) + && old_decl == 0 + && !MAIN_NAME_P (DECL_NAME (decl1))) + warning_at (loc, OPT_Wmissing_declarations, + "no previous declaration for %qD", + decl1); + /* Optionally warn of any def with no previous declaration + if the function has already been used. */ + else if (warn_missing_declarations + && old_decl != 0 + && old_decl != error_mark_node + && TREE_USED (old_decl) + && C_DECL_IMPLICIT (old_decl)) + warning_at (loc, OPT_Wmissing_declarations, + "%qD was used with no declaration before its definition", decl1); + + /* This function exists in static storage. + (This does not mean `static' in the C sense!) */ + TREE_STATIC (decl1) = 1; + + /* This is the earliest point at which we might know the assembler + name of the function. Thus, if it's set before this, die horribly. */ + gcc_assert (!DECL_ASSEMBLER_NAME_SET_P (decl1)); + + /* If #pragma weak was used, mark the decl weak now. */ + if (current_scope == file_scope) + maybe_apply_pragma_weak (decl1); + + /* Warn for unlikely, improbable, or stupid declarations of `main'. */ + if (warn_main && MAIN_NAME_P (DECL_NAME (decl1))) + { + if (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (decl1))) + != integer_type_node) + pedwarn (loc, OPT_Wmain, "return type of %qD is not %<int%>", decl1); + + check_main_parameter_types (decl1); + + if (!TREE_PUBLIC (decl1)) + pedwarn (loc, OPT_Wmain, + "%qD is normally a non-static function", decl1); + } + + /* 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); + + push_scope (); + declare_parm_level (); + + restype = TREE_TYPE (TREE_TYPE (current_function_decl)); + resdecl = build_decl (loc, RESULT_DECL, NULL_TREE, restype); + DECL_ARTIFICIAL (resdecl) = 1; + DECL_IGNORED_P (resdecl) = 1; + DECL_RESULT (current_function_decl) = resdecl; + + start_fname_decls (); + + return 1; +} + +/* Subroutine of store_parm_decls which handles new-style function + definitions (prototype format). The parms already have decls, so we + need only record them as in effect and complain if any redundant + old-style parm decls were written. */ +static void +store_parm_decls_newstyle (tree fndecl, const struct c_arg_info *arg_info) +{ + tree decl; + c_arg_tag *tag; + unsigned ix; + + if (current_scope->bindings) + { + error_at (DECL_SOURCE_LOCATION (fndecl), + "old-style parameter declarations in prototyped " + "function definition"); + + /* Get rid of the old-style declarations. */ + pop_scope (); + push_scope (); + } + /* Don't issue this warning for nested functions, and don't issue this + warning if we got here because ARG_INFO_TYPES was error_mark_node + (this happens when a function definition has just an ellipsis in + its parameter list). */ + else if (!in_system_header && !current_function_scope + && arg_info->types != error_mark_node) + warning_at (DECL_SOURCE_LOCATION (fndecl), OPT_Wtraditional, + "traditional C rejects ISO C style function definitions"); + + /* Now make all the parameter declarations visible in the function body. + We can bypass most of the grunt work of pushdecl. */ + for (decl = arg_info->parms; decl; decl = DECL_CHAIN (decl)) + { + DECL_CONTEXT (decl) = current_function_decl; + if (DECL_NAME (decl)) + { + bind (DECL_NAME (decl), decl, current_scope, + /*invisible=*/false, /*nested=*/false, + UNKNOWN_LOCATION); + if (!TREE_USED (decl)) + warn_if_shadowing (decl); + } + else + error_at (DECL_SOURCE_LOCATION (decl), "parameter name omitted"); + } + + /* Record the parameter list in the function declaration. */ + DECL_ARGUMENTS (fndecl) = arg_info->parms; + + /* Now make all the ancillary declarations visible, likewise. */ + for (decl = arg_info->others; decl; decl = DECL_CHAIN (decl)) + { + DECL_CONTEXT (decl) = current_function_decl; + if (DECL_NAME (decl)) + bind (DECL_NAME (decl), decl, current_scope, + /*invisible=*/false, + /*nested=*/(TREE_CODE (decl) == FUNCTION_DECL), + UNKNOWN_LOCATION); + } + + /* And all the tag declarations. */ + FOR_EACH_VEC_ELT_REVERSE (c_arg_tag, arg_info->tags, ix, tag) + if (tag->id) + bind (tag->id, tag->type, current_scope, + /*invisible=*/false, /*nested=*/false, UNKNOWN_LOCATION); +} + +/* Subroutine of store_parm_decls which handles old-style function + definitions (separate parameter list and declarations). */ + +static void +store_parm_decls_oldstyle (tree fndecl, const struct c_arg_info *arg_info) +{ + struct c_binding *b; + tree parm, decl, last; + tree parmids = arg_info->parms; + struct pointer_set_t *seen_args = pointer_set_create (); + + if (!in_system_header) + warning_at (DECL_SOURCE_LOCATION (fndecl), + OPT_Wold_style_definition, "old-style function definition"); + + /* Match each formal parameter name with its declaration. Save each + decl in the appropriate TREE_PURPOSE slot of the parmids chain. */ + for (parm = parmids; parm; parm = TREE_CHAIN (parm)) + { + if (TREE_VALUE (parm) == 0) + { + error_at (DECL_SOURCE_LOCATION (fndecl), + "parameter name missing from parameter list"); + TREE_PURPOSE (parm) = 0; + continue; + } + + b = I_SYMBOL_BINDING (TREE_VALUE (parm)); + if (b && B_IN_CURRENT_SCOPE (b)) + { + decl = b->decl; + /* Skip erroneous parameters. */ + if (decl == error_mark_node) + continue; + /* If we got something other than a PARM_DECL it is an error. */ + if (TREE_CODE (decl) != PARM_DECL) + error_at (DECL_SOURCE_LOCATION (decl), + "%qD declared as a non-parameter", decl); + /* If the declaration is already marked, we have a duplicate + name. Complain and ignore the duplicate. */ + else if (pointer_set_contains (seen_args, decl)) + { + error_at (DECL_SOURCE_LOCATION (decl), + "multiple parameters named %qD", decl); + TREE_PURPOSE (parm) = 0; + continue; + } + /* If the declaration says "void", complain and turn it into + an int. */ + else if (VOID_TYPE_P (TREE_TYPE (decl))) + { + error_at (DECL_SOURCE_LOCATION (decl), + "parameter %qD declared with void type", decl); + TREE_TYPE (decl) = integer_type_node; + DECL_ARG_TYPE (decl) = integer_type_node; + layout_decl (decl, 0); + } + warn_if_shadowing (decl); + } + /* If no declaration found, default to int. */ + else + { + /* FIXME diagnostics: This should be the location of the argument, + not the FNDECL. E.g., for an old-style declaration + + int f10(v) { blah; } + + We should use the location of the V, not the F10. + Unfortunately, the V is an IDENTIFIER_NODE which has no + location. In the future we need locations for c_arg_info + entries. + + See gcc.dg/Wshadow-3.c for an example of this problem. */ + decl = build_decl (DECL_SOURCE_LOCATION (fndecl), + PARM_DECL, TREE_VALUE (parm), integer_type_node); + DECL_ARG_TYPE (decl) = TREE_TYPE (decl); + pushdecl (decl); + warn_if_shadowing (decl); + + if (flag_isoc99) + pedwarn (DECL_SOURCE_LOCATION (decl), + 0, "type of %qD defaults to %<int%>", decl); + else + warning_at (DECL_SOURCE_LOCATION (decl), + OPT_Wmissing_parameter_type, + "type of %qD defaults to %<int%>", decl); + } + + TREE_PURPOSE (parm) = decl; + pointer_set_insert (seen_args, decl); + } + + /* Now examine the parms chain for incomplete declarations + and declarations with no corresponding names. */ + + for (b = current_scope->bindings; b; b = b->prev) + { + parm = b->decl; + if (TREE_CODE (parm) != PARM_DECL) + continue; + + if (TREE_TYPE (parm) != error_mark_node + && !COMPLETE_TYPE_P (TREE_TYPE (parm))) + { + error_at (DECL_SOURCE_LOCATION (parm), + "parameter %qD has incomplete type", parm); + TREE_TYPE (parm) = error_mark_node; + } + + if (!pointer_set_contains (seen_args, parm)) + { + error_at (DECL_SOURCE_LOCATION (parm), + "declaration for parameter %qD but no such parameter", + parm); + + /* Pretend the parameter was not missing. + This gets us to a standard state and minimizes + further error messages. */ + parmids = chainon (parmids, tree_cons (parm, 0, 0)); + } + } + + /* Chain the declarations together in the order of the list of + names. Store that chain in the function decl, replacing the + list of names. Update the current scope to match. */ + DECL_ARGUMENTS (fndecl) = 0; + + for (parm = parmids; parm; parm = TREE_CHAIN (parm)) + if (TREE_PURPOSE (parm)) + break; + if (parm && TREE_PURPOSE (parm)) + { + last = TREE_PURPOSE (parm); + DECL_ARGUMENTS (fndecl) = last; + + for (parm = TREE_CHAIN (parm); parm; parm = TREE_CHAIN (parm)) + if (TREE_PURPOSE (parm)) + { + DECL_CHAIN (last) = TREE_PURPOSE (parm); + last = TREE_PURPOSE (parm); + } + DECL_CHAIN (last) = 0; + } + + pointer_set_destroy (seen_args); + + /* 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 (current_function_prototype_arg_types) + { + tree type; + for (parm = DECL_ARGUMENTS (fndecl), + type = current_function_prototype_arg_types; + parm || (type && TREE_VALUE (type) != error_mark_node + && (TYPE_MAIN_VARIANT (TREE_VALUE (type)) != void_type_node)); + parm = DECL_CHAIN (parm), type = TREE_CHAIN (type)) + { + if (parm == 0 || type == 0 + || TYPE_MAIN_VARIANT (TREE_VALUE (type)) == void_type_node) + { + if (current_function_prototype_built_in) + warning_at (DECL_SOURCE_LOCATION (fndecl), + 0, "number of arguments doesn%'t match " + "built-in prototype"); + else + { + /* FIXME diagnostics: This should be the location of + FNDECL, but there is bug when a prototype is + declared inside function context, but defined + outside of it (e.g., gcc.dg/pr15698-2.c). In + which case FNDECL gets the location of the + prototype, not the definition. */ + error_at (input_location, + "number of arguments doesn%'t match prototype"); + + error_at (current_function_prototype_locus, + "prototype declaration"); + } + break; + } + /* Type for passing arg must be consistent with that + declared for the arg. ISO C says we take the unqualified + type for parameters declared with qualified type. */ + if (TREE_TYPE (parm) != error_mark_node + && TREE_TYPE (type) != error_mark_node + && !comptypes (TYPE_MAIN_VARIANT (DECL_ARG_TYPE (parm)), + TYPE_MAIN_VARIANT (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); + + if (targetm.calls.promote_prototypes (TREE_TYPE (current_function_decl)) + && INTEGRAL_TYPE_P (TREE_TYPE (parm)) + && TYPE_PRECISION (TREE_TYPE (parm)) + < TYPE_PRECISION (integer_type_node)) + DECL_ARG_TYPE (parm) = integer_type_node; + + /* ??? Is it possible to get here with a + built-in prototype or will it always have + been diagnosed as conflicting with an + old-style definition and discarded? */ + if (current_function_prototype_built_in) + warning_at (DECL_SOURCE_LOCATION (parm), + OPT_Wpedantic, "promoted argument %qD " + "doesn%'t match built-in prototype", parm); + else + { + pedwarn (DECL_SOURCE_LOCATION (parm), + OPT_Wpedantic, "promoted argument %qD " + "doesn%'t match prototype", parm); + pedwarn (current_function_prototype_locus, OPT_Wpedantic, + "prototype declaration"); + } + } + else + { + if (current_function_prototype_built_in) + warning_at (DECL_SOURCE_LOCATION (parm), + 0, "argument %qD doesn%'t match " + "built-in prototype", parm); + else + { + error_at (DECL_SOURCE_LOCATION (parm), + "argument %qD doesn%'t match prototype", parm); + error_at (current_function_prototype_locus, + "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 = DECL_CHAIN (parm)) + { + type = tree_cons (NULL_TREE, DECL_ARG_TYPE (parm), NULL_TREE); + if (last) + TREE_CHAIN (last) = type; + else + actual = type; + last = type; + } + type = 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_variant_type_copy (TREE_TYPE (fndecl)); + + TYPE_ACTUAL_ARG_TYPES (TREE_TYPE (fndecl)) = actual; + } +} + +/* Store parameter declarations passed in ARG_INFO into the current + function declaration. */ + +void +store_parm_decls_from (struct c_arg_info *arg_info) +{ + current_function_arg_info = arg_info; + store_parm_decls (); +} + +/* 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, construct a prototype out of the old-style + parameter declarations and inject it into the function's type. */ + +void +store_parm_decls (void) +{ + tree fndecl = current_function_decl; + bool proto; + + /* The argument information block for FNDECL. */ + struct c_arg_info *arg_info = current_function_arg_info; + current_function_arg_info = 0; + + /* True if this definition is written with a prototype. Note: + despite C99 6.7.5.3p14, we can *not* treat an empty argument + list in a function definition as equivalent to (void) -- an + empty argument list specifies the function has no parameters, + but only (void) sets up a prototype for future calls. */ + proto = arg_info->types != 0; + + if (proto) + store_parm_decls_newstyle (fndecl, arg_info); + else + store_parm_decls_oldstyle (fndecl, arg_info); + + /* The next call to push_scope will be a function body. */ + + next_is_function_body = true; + + /* Write a record describing this function definition to the prototypes + file (if requested). */ + + gen_aux_info_record (fndecl, 1, 0, proto); + + /* Initialize the RTL code for the function. */ + allocate_struct_function (fndecl, false); + + if (warn_unused_local_typedefs) + cfun->language = ggc_alloc_cleared_language_function (); + + /* Begin the statement tree for this function. */ + DECL_SAVED_TREE (fndecl) = push_stmt_list (); + + /* ??? Insert the contents of the pending sizes list into the function + to be evaluated. The only reason left to have this is + void foo(int n, int array[n++]) + because we throw away the array type in favor of a pointer type, and + thus won't naturally see the SAVE_EXPR containing the increment. All + other pending sizes would be handled by gimplify_parameters. */ + if (arg_info->pending_sizes) + add_stmt (arg_info->pending_sizes); +} + + +/* Finish up a function declaration and compile that function + all the way to assembler language output. Then free the storage + for the function definition. + + This is called after parsing the body of the function definition. */ + +void +finish_function (void) +{ + tree fndecl = current_function_decl; + + if (c_dialect_objc ()) + objc_finish_function (); + + if (TREE_CODE (fndecl) == FUNCTION_DECL + && targetm.calls.promote_prototypes (TREE_TYPE (fndecl))) + { + tree args = DECL_ARGUMENTS (fndecl); + for (; args; args = DECL_CHAIN (args)) + { + tree type = TREE_TYPE (args); + if (INTEGRAL_TYPE_P (type) + && TYPE_PRECISION (type) < TYPE_PRECISION (integer_type_node)) + DECL_ARG_TYPE (args) = integer_type_node; + } + } + + if (DECL_INITIAL (fndecl) && DECL_INITIAL (fndecl) != error_mark_node) + BLOCK_SUPERCONTEXT (DECL_INITIAL (fndecl)) = fndecl; + + /* Must mark the RESULT_DECL as being in this function. */ + + if (DECL_RESULT (fndecl) && DECL_RESULT (fndecl) != error_mark_node) + DECL_CONTEXT (DECL_RESULT (fndecl)) = fndecl; + + if (MAIN_NAME_P (DECL_NAME (fndecl)) && flag_hosted + && TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (fndecl))) + == integer_type_node && flag_isoc99) + { + /* Hack. We don't want the middle-end to warn that this return + is unreachable, so we mark its location as special. Using + UNKNOWN_LOCATION has the problem that it gets clobbered in + annotate_one_with_locus. A cleaner solution might be to + ensure ! should_carry_locus_p (stmt), but that needs a flag. + */ + c_finish_return (BUILTINS_LOCATION, integer_zero_node, NULL_TREE); + } + + /* Tie off the statement tree for this function. */ + DECL_SAVED_TREE (fndecl) = pop_stmt_list (DECL_SAVED_TREE (fndecl)); + + finish_fname_decls (); + + /* Complain if there's just no return statement. */ + if (warn_return_type + && TREE_CODE (TREE_TYPE (TREE_TYPE (fndecl))) != VOID_TYPE + && !current_function_returns_value && !current_function_returns_null + /* Don't complain if we are no-return. */ + && !current_function_returns_abnormally + /* Don't complain if we are declared noreturn. */ + && !TREE_THIS_VOLATILE (fndecl) + /* Don't warn for main(). */ + && !MAIN_NAME_P (DECL_NAME (fndecl)) + /* Or if they didn't actually specify a return type. */ + && !C_FUNCTION_IMPLICIT_INT (fndecl) + /* Normally, with -Wreturn-type, flow will complain, but we might + optimize out static functions. */ + && !TREE_PUBLIC (fndecl)) + { + warning (OPT_Wreturn_type, + "no return statement in function returning non-void"); + TREE_NO_WARNING (fndecl) = 1; + } + + /* Complain about parameters that are only set, but never otherwise used. */ + if (warn_unused_but_set_parameter) + { + tree decl; + + for (decl = DECL_ARGUMENTS (fndecl); + decl; + decl = DECL_CHAIN (decl)) + if (TREE_USED (decl) + && TREE_CODE (decl) == PARM_DECL + && !DECL_READ_P (decl) + && DECL_NAME (decl) + && !DECL_ARTIFICIAL (decl) + && !TREE_NO_WARNING (decl)) + warning_at (DECL_SOURCE_LOCATION (decl), + OPT_Wunused_but_set_parameter, + "parameter %qD set but not used", decl); + } + + /* Complain about locally defined typedefs that are not used in this + function. */ + maybe_warn_unused_local_typedefs (); + + /* Store the end of the function, so that we get good line number + info for the epilogue. */ + cfun->function_end_locus = input_location; + + /* Finalize the ELF visibility for the function. */ + c_determine_visibility (fndecl); + + /* For GNU C extern inline functions disregard inline limits. */ + if (DECL_EXTERNAL (fndecl) + && DECL_DECLARED_INLINE_P (fndecl)) + DECL_DISREGARD_INLINE_LIMITS (fndecl) = 1; + + /* Genericize before inlining. Delay genericizing nested functions + until their parent function is genericized. Since finalizing + requires GENERIC, delay that as well. */ + + if (DECL_INITIAL (fndecl) && DECL_INITIAL (fndecl) != error_mark_node + && !undef_nested_function) + { + if (!decl_function_context (fndecl)) + { + invoke_plugin_callbacks (PLUGIN_PRE_GENERICIZE, fndecl); + c_genericize (fndecl); + + /* ??? Objc emits functions after finalizing the compilation unit. + This should be cleaned up later and this conditional removed. */ + if (cgraph_global_info_ready) + { + cgraph_add_new_function (fndecl, false); + return; + } + cgraph_finalize_function (fndecl, false); + } + else + { + /* Register this function with cgraph just far enough to get it + added to our parent's nested function list. Handy, since the + C front end doesn't have such a list. */ + (void) cgraph_get_create_node (fndecl); + } + } + + if (!decl_function_context (fndecl)) + undef_nested_function = false; + + if (cfun->language != NULL) + { + ggc_free (cfun->language); + cfun->language = NULL; + } + + /* We're leaving the context of this function, so zap cfun. + It's still in DECL_STRUCT_FUNCTION, and we'll restore it in + tree_rest_of_compilation. */ + set_cfun (NULL); + current_function_decl = NULL; +} + +/* Check the declarations given in a for-loop for satisfying the C99 + constraints. If exactly one such decl is found, return it. LOC is + the location of the opening parenthesis of the for loop. The last + parameter allows you to control the "for loop initial declarations + are only allowed in C99 mode". Normally, you should pass + flag_isoc99 as that parameter. But in some cases (Objective-C + foreach loop, for example) we want to run the checks in this + function even if not in C99 mode, so we allow the caller to turn + off the error about not being in C99 mode. +*/ + +tree +check_for_loop_decls (location_t loc, bool turn_off_iso_c99_error) +{ + struct c_binding *b; + tree one_decl = NULL_TREE; + int n_decls = 0; + + if (!turn_off_iso_c99_error) + { + static bool hint = true; + /* If we get here, declarations have been used in a for loop without + the C99 for loop scope. This doesn't make much sense, so don't + allow it. */ + error_at (loc, "%<for%> loop initial declarations " + "are only allowed in C99 mode"); + if (hint) + { + inform (loc, + "use option -std=c99 or -std=gnu99 to compile your code"); + hint = false; + } + return NULL_TREE; + } + /* C99 subclause 6.8.5 paragraph 3: + + [#3] The declaration part of a for statement shall only + declare identifiers for objects having storage class auto or + register. + + It isn't clear whether, in this sentence, "identifiers" binds to + "shall only declare" or to "objects" - that is, whether all identifiers + declared must be identifiers for objects, or whether the restriction + only applies to those that are. (A question on this in comp.std.c + in November 2000 received no answer.) We implement the strictest + interpretation, to avoid creating an extension which later causes + problems. */ + + for (b = current_scope->bindings; b; b = b->prev) + { + tree id = b->id; + tree decl = b->decl; + + if (!id) + continue; + + switch (TREE_CODE (decl)) + { + case VAR_DECL: + { + location_t decl_loc = DECL_SOURCE_LOCATION (decl); + if (TREE_STATIC (decl)) + error_at (decl_loc, + "declaration of static variable %qD in %<for%> loop " + "initial declaration", decl); + else if (DECL_EXTERNAL (decl)) + error_at (decl_loc, + "declaration of %<extern%> variable %qD in %<for%> loop " + "initial declaration", decl); + } + break; + + case RECORD_TYPE: + error_at (loc, + "%<struct %E%> declared in %<for%> loop initial " + "declaration", id); + break; + case UNION_TYPE: + error_at (loc, + "%<union %E%> declared in %<for%> loop initial declaration", + id); + break; + case ENUMERAL_TYPE: + error_at (loc, "%<enum %E%> declared in %<for%> loop " + "initial declaration", id); + break; + default: + error_at (loc, "declaration of non-variable " + "%qD in %<for%> loop initial declaration", decl); + } + + n_decls++; + one_decl = decl; + } + + return n_decls == 1 ? one_decl : NULL_TREE; +} + +/* Save and reinitialize the variables + used during compilation of a C function. */ + +void +c_push_function_context (void) +{ + struct language_function *p = cfun->language; + /* cfun->language might have been already allocated by the use of + -Wunused-local-typedefs. In that case, just re-use it. */ + if (p == NULL) + cfun->language = p = ggc_alloc_cleared_language_function (); + + p->base.x_stmt_tree = c_stmt_tree; + c_stmt_tree.x_cur_stmt_list + = VEC_copy (tree, gc, c_stmt_tree.x_cur_stmt_list); + p->x_break_label = c_break_label; + p->x_cont_label = c_cont_label; + p->x_switch_stack = c_switch_stack; + p->arg_info = current_function_arg_info; + p->returns_value = current_function_returns_value; + p->returns_null = current_function_returns_null; + p->returns_abnormally = current_function_returns_abnormally; + p->warn_about_return_type = warn_about_return_type; + + push_function_context (); +} + +/* Restore the variables used during compilation of a C function. */ + +void +c_pop_function_context (void) +{ + struct language_function *p; + + pop_function_context (); + p = cfun->language; + + /* When -Wunused-local-typedefs is in effect, cfun->languages is + used to store data throughout the life time of the current cfun, + So don't deallocate it. */ + if (!warn_unused_local_typedefs) + cfun->language = NULL; + + if (DECL_STRUCT_FUNCTION (current_function_decl) == 0 + && DECL_SAVED_TREE (current_function_decl) == NULL_TREE) + { + /* 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; + } + + c_stmt_tree = p->base.x_stmt_tree; + p->base.x_stmt_tree.x_cur_stmt_list = NULL; + c_break_label = p->x_break_label; + c_cont_label = p->x_cont_label; + c_switch_stack = p->x_switch_stack; + current_function_arg_info = p->arg_info; + current_function_returns_value = p->returns_value; + current_function_returns_null = p->returns_null; + current_function_returns_abnormally = p->returns_abnormally; + warn_about_return_type = p->warn_about_return_type; +} + +/* The functions below are required for functionality of doing + function at once processing in the C front end. Currently these + functions are not called from anywhere in the C front end, but as + these changes continue, that will change. */ + +/* Returns the stmt_tree (if any) to which statements are currently + being added. If there is no active statement-tree, NULL is + returned. */ + +stmt_tree +current_stmt_tree (void) +{ + return &c_stmt_tree; +} + +/* Return the global value of T as a symbol. */ + +tree +identifier_global_value (tree t) +{ + struct c_binding *b; + + for (b = I_SYMBOL_BINDING (t); b; b = b->shadowed) + if (B_IN_FILE_SCOPE (b) || B_IN_EXTERNAL_SCOPE (b)) + return b->decl; + + return 0; +} + +/* In C, the only C-linkage public declaration is at file scope. */ + +tree +c_linkage_bindings (tree name) +{ + return identifier_global_value (name); +} + +/* Record a builtin type for C. If NAME is non-NULL, it is the name used; + otherwise the name is found in ridpointers from RID_INDEX. */ + +void +record_builtin_type (enum rid rid_index, const char *name, tree type) +{ + tree id, decl; + if (name == 0) + id = ridpointers[(int) rid_index]; + else + id = get_identifier (name); + decl = build_decl (UNKNOWN_LOCATION, TYPE_DECL, id, type); + pushdecl (decl); + if (debug_hooks->type_decl) + debug_hooks->type_decl (decl, false); +} + +/* Build the void_list_node (void_type_node having been created). */ +tree +build_void_list_node (void) +{ + tree t = build_tree_list (NULL_TREE, void_type_node); + return t; +} + +/* Return a c_parm structure with the given SPECS, ATTRS and DECLARATOR. */ + +struct c_parm * +build_c_parm (struct c_declspecs *specs, tree attrs, + struct c_declarator *declarator) +{ + struct c_parm *ret = XOBNEW (&parser_obstack, struct c_parm); + ret->specs = specs; + ret->attrs = attrs; + ret->declarator = declarator; + return ret; +} + +/* Return a declarator with nested attributes. TARGET is the inner + declarator to which these attributes apply. ATTRS are the + attributes. */ + +struct c_declarator * +build_attrs_declarator (tree attrs, struct c_declarator *target) +{ + struct c_declarator *ret = XOBNEW (&parser_obstack, struct c_declarator); + ret->kind = cdk_attrs; + ret->declarator = target; + ret->u.attrs = attrs; + return ret; +} + +/* Return a declarator for a function with arguments specified by ARGS + and return type specified by TARGET. */ + +struct c_declarator * +build_function_declarator (struct c_arg_info *args, + struct c_declarator *target) +{ + struct c_declarator *ret = XOBNEW (&parser_obstack, struct c_declarator); + ret->kind = cdk_function; + ret->declarator = target; + ret->u.arg_info = args; + return ret; +} + +/* Return a declarator for the identifier IDENT (which may be + NULL_TREE for an abstract declarator). */ + +struct c_declarator * +build_id_declarator (tree ident) +{ + struct c_declarator *ret = XOBNEW (&parser_obstack, struct c_declarator); + ret->kind = cdk_id; + ret->declarator = 0; + ret->u.id = ident; + /* Default value - may get reset to a more precise location. */ + ret->id_loc = input_location; + return ret; +} + +/* Return something to represent absolute declarators containing a *. + TARGET is the absolute declarator that the * contains. + TYPE_QUALS_ATTRS is a structure for type qualifiers and attributes + to apply to the pointer type. */ + +struct c_declarator * +make_pointer_declarator (struct c_declspecs *type_quals_attrs, + struct c_declarator *target) +{ + tree attrs; + int quals = 0; + struct c_declarator *itarget = target; + struct c_declarator *ret = XOBNEW (&parser_obstack, struct c_declarator); + if (type_quals_attrs) + { + attrs = type_quals_attrs->attrs; + quals = quals_from_declspecs (type_quals_attrs); + if (attrs != NULL_TREE) + itarget = build_attrs_declarator (attrs, target); + } + ret->kind = cdk_pointer; + ret->declarator = itarget; + ret->u.pointer_quals = quals; + return ret; +} + +/* Return a pointer to a structure for an empty list of declaration + specifiers. */ + +struct c_declspecs * +build_null_declspecs (void) +{ + struct c_declspecs *ret = XOBNEW (&parser_obstack, struct c_declspecs); + memset (&ret->locations, 0, cdw_number_of_elements); + ret->type = 0; + ret->expr = 0; + ret->decl_attr = 0; + ret->attrs = 0; + ret->align_log = -1; + ret->typespec_word = cts_none; + ret->storage_class = csc_none; + ret->expr_const_operands = true; + ret->declspecs_seen_p = false; + ret->typespec_kind = ctsk_none; + ret->non_sc_seen_p = false; + ret->typedef_p = false; + ret->explicit_signed_p = false; + ret->deprecated_p = false; + ret->default_int_p = false; + ret->long_p = false; + ret->long_long_p = false; + ret->short_p = false; + ret->signed_p = false; + ret->unsigned_p = false; + ret->complex_p = false; + ret->inline_p = false; + ret->noreturn_p = false; + ret->thread_p = false; + ret->const_p = false; + ret->volatile_p = false; + ret->restrict_p = false; + ret->saturating_p = false; + ret->alignas_p = false; + ret->address_space = ADDR_SPACE_GENERIC; + return ret; +} + +/* Add the address space ADDRSPACE to the declaration specifiers + SPECS, returning SPECS. */ + +struct c_declspecs * +declspecs_add_addrspace (source_location location, + struct c_declspecs *specs, addr_space_t as) +{ + specs->non_sc_seen_p = true; + specs->declspecs_seen_p = true; + + if (!ADDR_SPACE_GENERIC_P (specs->address_space) + && specs->address_space != as) + error ("incompatible address space qualifiers %qs and %qs", + c_addr_space_name (as), + c_addr_space_name (specs->address_space)); + else + { + specs->address_space = as; + specs->locations[cdw_address_space] = location; + } + return specs; +} + +/* Add the type qualifier QUAL to the declaration specifiers SPECS, + returning SPECS. */ + +struct c_declspecs * +declspecs_add_qual (source_location loc, + struct c_declspecs *specs, tree qual) +{ + enum rid i; + bool dupe = false; + specs->non_sc_seen_p = true; + specs->declspecs_seen_p = true; + gcc_assert (TREE_CODE (qual) == IDENTIFIER_NODE + && C_IS_RESERVED_WORD (qual)); + i = C_RID_CODE (qual); + switch (i) + { + case RID_CONST: + dupe = specs->const_p; + specs->const_p = true; + specs->locations[cdw_const] = loc; + break; + case RID_VOLATILE: + dupe = specs->volatile_p; + specs->volatile_p = true; + specs->locations[cdw_volatile] = loc; + break; + case RID_RESTRICT: + dupe = specs->restrict_p; + specs->restrict_p = true; + specs->locations[cdw_restrict] = loc; + break; + default: + gcc_unreachable (); + } + if (dupe && !flag_isoc99) + pedwarn (loc, OPT_Wpedantic, "duplicate %qE", qual); + return specs; +} + +/* Add the type specifier TYPE to the declaration specifiers SPECS, + returning SPECS. */ + +struct c_declspecs * +declspecs_add_type (location_t loc, struct c_declspecs *specs, + struct c_typespec spec) +{ + tree type = spec.spec; + specs->non_sc_seen_p = true; + specs->declspecs_seen_p = true; + specs->typespec_kind = spec.kind; + if (TREE_DEPRECATED (type)) + specs->deprecated_p = true; + + /* Handle type specifier keywords. */ + if (TREE_CODE (type) == IDENTIFIER_NODE + && C_IS_RESERVED_WORD (type) + && C_RID_CODE (type) != RID_CXX_COMPAT_WARN) + { + enum rid i = C_RID_CODE (type); + if (specs->type) + { + error_at (loc, "two or more data types in declaration specifiers"); + return specs; + } + if ((int) i <= (int) RID_LAST_MODIFIER) + { + /* "long", "short", "signed", "unsigned", "_Complex" or "_Sat". */ + bool dupe = false; + switch (i) + { + case RID_LONG: + if (specs->long_long_p) + { + error_at (loc, "%<long long long%> is too long for GCC"); + break; + } + if (specs->long_p) + { + if (specs->typespec_word == cts_double) + { + error_at (loc, + ("both %<long long%> and %<double%> in " + "declaration specifiers")); + break; + } + pedwarn_c90 (loc, OPT_Wlong_long, + "ISO C90 does not support %<long long%>"); + specs->long_long_p = 1; + specs->locations[cdw_long_long] = loc; + break; + } + if (specs->short_p) + error_at (loc, + ("both %<long%> and %<short%> in " + "declaration specifiers")); + else if (specs->typespec_word == cts_void) + error_at (loc, + ("both %<long%> and %<void%> in " + "declaration specifiers")); + else if (specs->typespec_word == cts_int128) + error_at (loc, + ("both %<long%> and %<__int128%> in " + "declaration specifiers")); + else if (specs->typespec_word == cts_bool) + error_at (loc, + ("both %<long%> and %<_Bool%> in " + "declaration specifiers")); + else if (specs->typespec_word == cts_char) + error_at (loc, + ("both %<long%> and %<char%> in " + "declaration specifiers")); + else if (specs->typespec_word == cts_float) + error_at (loc, + ("both %<long%> and %<float%> in " + "declaration specifiers")); + else if (specs->typespec_word == cts_dfloat32) + error_at (loc, + ("both %<long%> and %<_Decimal32%> in " + "declaration specifiers")); + else if (specs->typespec_word == cts_dfloat64) + error_at (loc, + ("both %<long%> and %<_Decimal64%> in " + "declaration specifiers")); + else if (specs->typespec_word == cts_dfloat128) + error_at (loc, + ("both %<long%> and %<_Decimal128%> in " + "declaration specifiers")); + else + { + specs->long_p = true; + specs->locations[cdw_long] = loc; + } + break; + case RID_SHORT: + dupe = specs->short_p; + if (specs->long_p) + error_at (loc, + ("both %<long%> and %<short%> in " + "declaration specifiers")); + else if (specs->typespec_word == cts_void) + error_at (loc, + ("both %<short%> and %<void%> in " + "declaration specifiers")); + else if (specs->typespec_word == cts_int128) + error_at (loc, + ("both %<short%> and %<__int128%> in " + "declaration specifiers")); + else if (specs->typespec_word == cts_bool) + error_at (loc, + ("both %<short%> and %<_Bool%> in " + "declaration specifiers")); + else if (specs->typespec_word == cts_char) + error_at (loc, + ("both %<short%> and %<char%> in " + "declaration specifiers")); + else if (specs->typespec_word == cts_float) + error_at (loc, + ("both %<short%> and %<float%> in " + "declaration specifiers")); + else if (specs->typespec_word == cts_double) + error_at (loc, + ("both %<short%> and %<double%> in " + "declaration specifiers")); + else if (specs->typespec_word == cts_dfloat32) + error_at (loc, + ("both %<short%> and %<_Decimal32%> in " + "declaration specifiers")); + else if (specs->typespec_word == cts_dfloat64) + error_at (loc, + ("both %<short%> and %<_Decimal64%> in " + "declaration specifiers")); + else if (specs->typespec_word == cts_dfloat128) + error_at (loc, + ("both %<short%> and %<_Decimal128%> in " + "declaration specifiers")); + else + { + specs->short_p = true; + specs->locations[cdw_short] = loc; + } + break; + case RID_SIGNED: + dupe = specs->signed_p; + if (specs->unsigned_p) + error_at (loc, + ("both %<signed%> and %<unsigned%> in " + "declaration specifiers")); + else if (specs->typespec_word == cts_void) + error_at (loc, + ("both %<signed%> and %<void%> in " + "declaration specifiers")); + else if (specs->typespec_word == cts_bool) + error_at (loc, + ("both %<signed%> and %<_Bool%> in " + "declaration specifiers")); + else if (specs->typespec_word == cts_float) + error_at (loc, + ("both %<signed%> and %<float%> in " + "declaration specifiers")); + else if (specs->typespec_word == cts_double) + error_at (loc, + ("both %<signed%> and %<double%> in " + "declaration specifiers")); + else if (specs->typespec_word == cts_dfloat32) + error_at (loc, + ("both %<signed%> and %<_Decimal32%> in " + "declaration specifiers")); + else if (specs->typespec_word == cts_dfloat64) + error_at (loc, + ("both %<signed%> and %<_Decimal64%> in " + "declaration specifiers")); + else if (specs->typespec_word == cts_dfloat128) + error_at (loc, + ("both %<signed%> and %<_Decimal128%> in " + "declaration specifiers")); + else + { + specs->signed_p = true; + specs->locations[cdw_signed] = loc; + } + break; + case RID_UNSIGNED: + dupe = specs->unsigned_p; + if (specs->signed_p) + error_at (loc, + ("both %<signed%> and %<unsigned%> in " + "declaration specifiers")); + else if (specs->typespec_word == cts_void) + error_at (loc, + ("both %<unsigned%> and %<void%> in " + "declaration specifiers")); + else if (specs->typespec_word == cts_bool) + error_at (loc, + ("both %<unsigned%> and %<_Bool%> in " + "declaration specifiers")); + else if (specs->typespec_word == cts_float) + error_at (loc, + ("both %<unsigned%> and %<float%> in " + "declaration specifiers")); + else if (specs->typespec_word == cts_double) + error_at (loc, + ("both %<unsigned%> and %<double%> in " + "declaration specifiers")); + else if (specs->typespec_word == cts_dfloat32) + error_at (loc, + ("both %<unsigned%> and %<_Decimal32%> in " + "declaration specifiers")); + else if (specs->typespec_word == cts_dfloat64) + error_at (loc, + ("both %<unsigned%> and %<_Decimal64%> in " + "declaration specifiers")); + else if (specs->typespec_word == cts_dfloat128) + error_at (loc, + ("both %<unsigned%> and %<_Decimal128%> in " + "declaration specifiers")); + else + { + specs->unsigned_p = true; + specs->locations[cdw_unsigned] = loc; + } + break; + case RID_COMPLEX: + dupe = specs->complex_p; + if (!flag_isoc99 && !in_system_header_at (loc)) + pedwarn (loc, OPT_Wpedantic, + "ISO C90 does not support complex types"); + if (specs->typespec_word == cts_void) + error_at (loc, + ("both %<complex%> and %<void%> in " + "declaration specifiers")); + else if (specs->typespec_word == cts_bool) + error_at (loc, + ("both %<complex%> and %<_Bool%> in " + "declaration specifiers")); + else if (specs->typespec_word == cts_dfloat32) + error_at (loc, + ("both %<complex%> and %<_Decimal32%> in " + "declaration specifiers")); + else if (specs->typespec_word == cts_dfloat64) + error_at (loc, + ("both %<complex%> and %<_Decimal64%> in " + "declaration specifiers")); + else if (specs->typespec_word == cts_dfloat128) + error_at (loc, + ("both %<complex%> and %<_Decimal128%> in " + "declaration specifiers")); + else if (specs->typespec_word == cts_fract) + error_at (loc, + ("both %<complex%> and %<_Fract%> in " + "declaration specifiers")); + else if (specs->typespec_word == cts_accum) + error_at (loc, + ("both %<complex%> and %<_Accum%> in " + "declaration specifiers")); + else if (specs->saturating_p) + error_at (loc, + ("both %<complex%> and %<_Sat%> in " + "declaration specifiers")); + else + { + specs->complex_p = true; + specs->locations[cdw_complex] = loc; + } + break; + case RID_SAT: + dupe = specs->saturating_p; + pedwarn (loc, OPT_Wpedantic, + "ISO C does not support saturating types"); + if (specs->typespec_word == cts_int128) + { + error_at (loc, + ("both %<_Sat%> and %<__int128%> in " + "declaration specifiers")); + } + else if (specs->typespec_word == cts_void) + error_at (loc, + ("both %<_Sat%> and %<void%> in " + "declaration specifiers")); + else if (specs->typespec_word == cts_bool) + error_at (loc, + ("both %<_Sat%> and %<_Bool%> in " + "declaration specifiers")); + else if (specs->typespec_word == cts_char) + error_at (loc, + ("both %<_Sat%> and %<char%> in " + "declaration specifiers")); + else if (specs->typespec_word == cts_int) + error_at (loc, + ("both %<_Sat%> and %<int%> in " + "declaration specifiers")); + else if (specs->typespec_word == cts_float) + error_at (loc, + ("both %<_Sat%> and %<float%> in " + "declaration specifiers")); + else if (specs->typespec_word == cts_double) + error_at (loc, + ("both %<_Sat%> and %<double%> in " + "declaration specifiers")); + else if (specs->typespec_word == cts_dfloat32) + error_at (loc, + ("both %<_Sat%> and %<_Decimal32%> in " + "declaration specifiers")); + else if (specs->typespec_word == cts_dfloat64) + error_at (loc, + ("both %<_Sat%> and %<_Decimal64%> in " + "declaration specifiers")); + else if (specs->typespec_word == cts_dfloat128) + error_at (loc, + ("both %<_Sat%> and %<_Decimal128%> in " + "declaration specifiers")); + else if (specs->complex_p) + error_at (loc, + ("both %<_Sat%> and %<complex%> in " + "declaration specifiers")); + else + { + specs->saturating_p = true; + specs->locations[cdw_saturating] = loc; + } + break; + default: + gcc_unreachable (); + } + + if (dupe) + error_at (loc, "duplicate %qE", type); + + return specs; + } + else + { + /* "void", "_Bool", "char", "int", "float", "double", "_Decimal32", + "__int128", "_Decimal64", "_Decimal128", "_Fract" or "_Accum". */ + if (specs->typespec_word != cts_none) + { + error_at (loc, + "two or more data types in declaration specifiers"); + return specs; + } + switch (i) + { + case RID_INT128: + if (int128_integer_type_node == NULL_TREE) + { + error_at (loc, "%<__int128%> is not supported for this target"); + return specs; + } + if (!in_system_header) + pedwarn (loc, OPT_Wpedantic, + "ISO C does not support %<__int128%> type"); + + if (specs->long_p) + error_at (loc, + ("both %<__int128%> and %<long%> in " + "declaration specifiers")); + else if (specs->saturating_p) + error_at (loc, + ("both %<_Sat%> and %<__int128%> in " + "declaration specifiers")); + else if (specs->short_p) + error_at (loc, + ("both %<__int128%> and %<short%> in " + "declaration specifiers")); + else + { + specs->typespec_word = cts_int128; + specs->locations[cdw_typespec] = loc; + } + return specs; + case RID_VOID: + if (specs->long_p) + error_at (loc, + ("both %<long%> and %<void%> in " + "declaration specifiers")); + else if (specs->short_p) + error_at (loc, + ("both %<short%> and %<void%> in " + "declaration specifiers")); + else if (specs->signed_p) + error_at (loc, + ("both %<signed%> and %<void%> in " + "declaration specifiers")); + else if (specs->unsigned_p) + error_at (loc, + ("both %<unsigned%> and %<void%> in " + "declaration specifiers")); + else if (specs->complex_p) + error_at (loc, + ("both %<complex%> and %<void%> in " + "declaration specifiers")); + else if (specs->saturating_p) + error_at (loc, + ("both %<_Sat%> and %<void%> in " + "declaration specifiers")); + else + { + specs->typespec_word = cts_void; + specs->locations[cdw_typespec] = loc; + } + return specs; + case RID_BOOL: + if (specs->long_p) + error_at (loc, + ("both %<long%> and %<_Bool%> in " + "declaration specifiers")); + else if (specs->short_p) + error_at (loc, + ("both %<short%> and %<_Bool%> in " + "declaration specifiers")); + else if (specs->signed_p) + error_at (loc, + ("both %<signed%> and %<_Bool%> in " + "declaration specifiers")); + else if (specs->unsigned_p) + error_at (loc, + ("both %<unsigned%> and %<_Bool%> in " + "declaration specifiers")); + else if (specs->complex_p) + error_at (loc, + ("both %<complex%> and %<_Bool%> in " + "declaration specifiers")); + else if (specs->saturating_p) + error_at (loc, + ("both %<_Sat%> and %<_Bool%> in " + "declaration specifiers")); + else + { + specs->typespec_word = cts_bool; + specs->locations[cdw_typespec] = loc; + } + return specs; + case RID_CHAR: + if (specs->long_p) + error_at (loc, + ("both %<long%> and %<char%> in " + "declaration specifiers")); + else if (specs->short_p) + error_at (loc, + ("both %<short%> and %<char%> in " + "declaration specifiers")); + else if (specs->saturating_p) + error_at (loc, + ("both %<_Sat%> and %<char%> in " + "declaration specifiers")); + else + { + specs->typespec_word = cts_char; + specs->locations[cdw_typespec] = loc; + } + return specs; + case RID_INT: + if (specs->saturating_p) + error_at (loc, + ("both %<_Sat%> and %<int%> in " + "declaration specifiers")); + else + { + specs->typespec_word = cts_int; + specs->locations[cdw_typespec] = loc; + } + return specs; + case RID_FLOAT: + if (specs->long_p) + error_at (loc, + ("both %<long%> and %<float%> in " + "declaration specifiers")); + else if (specs->short_p) + error_at (loc, + ("both %<short%> and %<float%> in " + "declaration specifiers")); + else if (specs->signed_p) + error_at (loc, + ("both %<signed%> and %<float%> in " + "declaration specifiers")); + else if (specs->unsigned_p) + error_at (loc, + ("both %<unsigned%> and %<float%> in " + "declaration specifiers")); + else if (specs->saturating_p) + error_at (loc, + ("both %<_Sat%> and %<float%> in " + "declaration specifiers")); + else + { + specs->typespec_word = cts_float; + specs->locations[cdw_typespec] = loc; + } + return specs; + case RID_DOUBLE: + if (specs->long_long_p) + error_at (loc, + ("both %<long long%> and %<double%> in " + "declaration specifiers")); + else if (specs->short_p) + error_at (loc, + ("both %<short%> and %<double%> in " + "declaration specifiers")); + else if (specs->signed_p) + error_at (loc, + ("both %<signed%> and %<double%> in " + "declaration specifiers")); + else if (specs->unsigned_p) + error_at (loc, + ("both %<unsigned%> and %<double%> in " + "declaration specifiers")); + else if (specs->saturating_p) + error_at (loc, + ("both %<_Sat%> and %<double%> in " + "declaration specifiers")); + else + { + specs->typespec_word = cts_double; + specs->locations[cdw_typespec] = loc; + } + return specs; + case RID_DFLOAT32: + case RID_DFLOAT64: + case RID_DFLOAT128: + { + const char *str; + if (i == RID_DFLOAT32) + str = "_Decimal32"; + else if (i == RID_DFLOAT64) + str = "_Decimal64"; + else + str = "_Decimal128"; + if (specs->long_long_p) + error_at (loc, + ("both %<long long%> and %<%s%> in " + "declaration specifiers"), + str); + if (specs->long_p) + error_at (loc, + ("both %<long%> and %<%s%> in " + "declaration specifiers"), + str); + else if (specs->short_p) + error_at (loc, + ("both %<short%> and %<%s%> in " + "declaration specifiers"), + str); + else if (specs->signed_p) + error_at (loc, + ("both %<signed%> and %<%s%> in " + "declaration specifiers"), + str); + else if (specs->unsigned_p) + error_at (loc, + ("both %<unsigned%> and %<%s%> in " + "declaration specifiers"), + str); + else if (specs->complex_p) + error_at (loc, + ("both %<complex%> and %<%s%> in " + "declaration specifiers"), + str); + else if (specs->saturating_p) + error_at (loc, + ("both %<_Sat%> and %<%s%> in " + "declaration specifiers"), + str); + else if (i == RID_DFLOAT32) + specs->typespec_word = cts_dfloat32; + else if (i == RID_DFLOAT64) + specs->typespec_word = cts_dfloat64; + else + specs->typespec_word = cts_dfloat128; + specs->locations[cdw_typespec] = loc; + } + if (!targetm.decimal_float_supported_p ()) + error_at (loc, + ("decimal floating point not supported " + "for this target")); + pedwarn (loc, OPT_Wpedantic, + "ISO C does not support decimal floating point"); + return specs; + case RID_FRACT: + case RID_ACCUM: + { + const char *str; + if (i == RID_FRACT) + str = "_Fract"; + else + str = "_Accum"; + if (specs->complex_p) + error_at (loc, + ("both %<complex%> and %<%s%> in " + "declaration specifiers"), + str); + else if (i == RID_FRACT) + specs->typespec_word = cts_fract; + else + specs->typespec_word = cts_accum; + specs->locations[cdw_typespec] = loc; + } + if (!targetm.fixed_point_supported_p ()) + error_at (loc, + "fixed-point types not supported for this target"); + pedwarn (loc, OPT_Wpedantic, + "ISO C does not support fixed-point types"); + return specs; + default: + /* ObjC reserved word "id", handled below. */ + break; + } + } + } + + /* Now we have a typedef (a TYPE_DECL node), an identifier (some + form of ObjC type, cases such as "int" and "long" being handled + above), a TYPE (struct, union, enum and typeof specifiers) or an + ERROR_MARK. In none of these cases may there have previously + been any type specifiers. */ + if (specs->type || specs->typespec_word != cts_none + || specs->long_p || specs->short_p || specs->signed_p + || specs->unsigned_p || specs->complex_p) + error_at (loc, "two or more data types in declaration specifiers"); + else if (TREE_CODE (type) == TYPE_DECL) + { + if (TREE_TYPE (type) == error_mark_node) + ; /* Allow the type to default to int to avoid cascading errors. */ + else + { + specs->type = TREE_TYPE (type); + specs->decl_attr = DECL_ATTRIBUTES (type); + specs->typedef_p = true; + specs->explicit_signed_p = C_TYPEDEF_EXPLICITLY_SIGNED (type); + specs->locations[cdw_typedef] = loc; + + /* If this typedef name is defined in a struct, then a C++ + lookup would return a different value. */ + if (warn_cxx_compat + && I_SYMBOL_BINDING (DECL_NAME (type))->in_struct) + warning_at (loc, OPT_Wc___compat, + "C++ lookup of %qD would return a field, not a type", + type); + + /* If we are parsing a struct, record that a struct field + used a typedef. */ + if (warn_cxx_compat && struct_parse_info != NULL) + VEC_safe_push (tree, heap, struct_parse_info->typedefs_seen, type); + } + } + else if (TREE_CODE (type) == IDENTIFIER_NODE) + { + tree t = lookup_name (type); + if (!t || TREE_CODE (t) != TYPE_DECL) + error_at (loc, "%qE fails to be a typedef or built in type", type); + else if (TREE_TYPE (t) == error_mark_node) + ; + else + { + specs->type = TREE_TYPE (t); + specs->locations[cdw_typespec] = loc; + } + } + else + { + if (TREE_CODE (type) != ERROR_MARK && spec.kind == ctsk_typeof) + { + specs->typedef_p = true; + specs->locations[cdw_typedef] = loc; + if (spec.expr) + { + if (specs->expr) + specs->expr = build2 (COMPOUND_EXPR, TREE_TYPE (spec.expr), + specs->expr, spec.expr); + else + specs->expr = spec.expr; + specs->expr_const_operands &= spec.expr_const_operands; + } + } + specs->type = type; + } + + return specs; +} + +/* Add the storage class specifier or function specifier SCSPEC to the + declaration specifiers SPECS, returning SPECS. */ + +struct c_declspecs * +declspecs_add_scspec (source_location loc, + struct c_declspecs *specs, + tree scspec) +{ + enum rid i; + enum c_storage_class n = csc_none; + bool dupe = false; + specs->declspecs_seen_p = true; + gcc_assert (TREE_CODE (scspec) == IDENTIFIER_NODE + && C_IS_RESERVED_WORD (scspec)); + i = C_RID_CODE (scspec); + if (specs->non_sc_seen_p) + warning (OPT_Wold_style_declaration, + "%qE is not at beginning of declaration", scspec); + switch (i) + { + case RID_INLINE: + /* C99 permits duplicate inline. Although of doubtful utility, + it seems simplest to permit it in gnu89 mode as well, as + there is also little utility in maintaining this as a + difference between gnu89 and C99 inline. */ + dupe = false; + specs->inline_p = true; + specs->locations[cdw_inline] = loc; + break; + case RID_NORETURN: + /* Duplicate _Noreturn is permitted. */ + dupe = false; + specs->noreturn_p = true; + specs->locations[cdw_noreturn] = loc; + break; + case RID_THREAD: + dupe = specs->thread_p; + if (specs->storage_class == csc_auto) + error ("%<__thread%> used with %<auto%>"); + else if (specs->storage_class == csc_register) + error ("%<__thread%> used with %<register%>"); + else if (specs->storage_class == csc_typedef) + error ("%<__thread%> used with %<typedef%>"); + else + { + specs->thread_p = true; + specs->locations[cdw_thread] = loc; + } + break; + case RID_AUTO: + n = csc_auto; + break; + case RID_EXTERN: + n = csc_extern; + /* Diagnose "__thread extern". */ + if (specs->thread_p) + error ("%<__thread%> before %<extern%>"); + break; + case RID_REGISTER: + n = csc_register; + break; + case RID_STATIC: + n = csc_static; + /* Diagnose "__thread static". */ + if (specs->thread_p) + error ("%<__thread%> before %<static%>"); + break; + case RID_TYPEDEF: + n = csc_typedef; + break; + default: + gcc_unreachable (); + } + if (n != csc_none && n == specs->storage_class) + dupe = true; + if (dupe) + error ("duplicate %qE", scspec); + if (n != csc_none) + { + if (specs->storage_class != csc_none && n != specs->storage_class) + { + error ("multiple storage classes in declaration specifiers"); + } + else + { + specs->storage_class = n; + specs->locations[cdw_storage_class] = loc; + if (n != csc_extern && n != csc_static && specs->thread_p) + { + error ("%<__thread%> used with %qE", scspec); + specs->thread_p = false; + } + } + } + return specs; +} + +/* Add the attributes ATTRS to the declaration specifiers SPECS, + returning SPECS. */ + +struct c_declspecs * +declspecs_add_attrs (source_location loc, struct c_declspecs *specs, tree attrs) +{ + specs->attrs = chainon (attrs, specs->attrs); + specs->locations[cdw_attributes] = loc; + specs->declspecs_seen_p = true; + return specs; +} + +/* Add an _Alignas specifier (expression ALIGN, or type whose + alignment is ALIGN) to the declaration specifiers SPECS, returning + SPECS. */ +struct c_declspecs * +declspecs_add_alignas (source_location loc, + struct c_declspecs *specs, tree align) +{ + int align_log; + specs->alignas_p = true; + specs->locations[cdw_alignas] = loc; + if (align == error_mark_node) + return specs; + align_log = check_user_alignment (align, true); + if (align_log > specs->align_log) + specs->align_log = align_log; + return specs; +} + +/* Combine "long", "short", "signed", "unsigned" and "_Complex" type + specifiers with any other type specifier to determine the resulting + type. This is where ISO C checks on complex types are made, since + "_Complex long" is a prefix of the valid ISO C type "_Complex long + double". */ + +struct c_declspecs * +finish_declspecs (struct c_declspecs *specs) +{ + /* If a type was specified as a whole, we have no modifiers and are + done. */ + if (specs->type != NULL_TREE) + { + gcc_assert (!specs->long_p && !specs->long_long_p && !specs->short_p + && !specs->signed_p && !specs->unsigned_p + && !specs->complex_p); + + /* Set a dummy type. */ + if (TREE_CODE (specs->type) == ERROR_MARK) + specs->type = integer_type_node; + return specs; + } + + /* If none of "void", "_Bool", "char", "int", "float" or "double" + has been specified, treat it as "int" unless "_Complex" is + present and there are no other specifiers. If we just have + "_Complex", it is equivalent to "_Complex double", but e.g. + "_Complex short" is equivalent to "_Complex short int". */ + if (specs->typespec_word == cts_none) + { + if (specs->saturating_p) + { + error_at (specs->locations[cdw_saturating], + "%<_Sat%> is used without %<_Fract%> or %<_Accum%>"); + if (!targetm.fixed_point_supported_p ()) + error_at (specs->locations[cdw_saturating], + "fixed-point types not supported for this target"); + specs->typespec_word = cts_fract; + } + else if (specs->long_p || specs->short_p + || specs->signed_p || specs->unsigned_p) + { + specs->typespec_word = cts_int; + } + else if (specs->complex_p) + { + specs->typespec_word = cts_double; + pedwarn (specs->locations[cdw_complex], OPT_Wpedantic, + "ISO C does not support plain %<complex%> meaning " + "%<double complex%>"); + } + else + { + specs->typespec_word = cts_int; + specs->default_int_p = true; + /* We don't diagnose this here because grokdeclarator will + give more specific diagnostics according to whether it is + a function definition. */ + } + } + + /* If "signed" was specified, record this to distinguish "int" and + "signed int" in the case of a bit-field with + -funsigned-bitfields. */ + specs->explicit_signed_p = specs->signed_p; + + /* Now compute the actual type. */ + switch (specs->typespec_word) + { + case cts_void: + gcc_assert (!specs->long_p && !specs->short_p + && !specs->signed_p && !specs->unsigned_p + && !specs->complex_p); + specs->type = void_type_node; + break; + case cts_bool: + gcc_assert (!specs->long_p && !specs->short_p + && !specs->signed_p && !specs->unsigned_p + && !specs->complex_p); + specs->type = boolean_type_node; + break; + case cts_char: + gcc_assert (!specs->long_p && !specs->short_p); + gcc_assert (!(specs->signed_p && specs->unsigned_p)); + if (specs->signed_p) + specs->type = signed_char_type_node; + else if (specs->unsigned_p) + specs->type = unsigned_char_type_node; + else + specs->type = char_type_node; + if (specs->complex_p) + { + pedwarn (specs->locations[cdw_complex], OPT_Wpedantic, + "ISO C does not support complex integer types"); + specs->type = build_complex_type (specs->type); + } + break; + case cts_int128: + gcc_assert (!specs->long_p && !specs->short_p && !specs->long_long_p); + gcc_assert (!(specs->signed_p && specs->unsigned_p)); + specs->type = (specs->unsigned_p + ? int128_unsigned_type_node + : int128_integer_type_node); + if (specs->complex_p) + { + pedwarn (specs->locations[cdw_complex], OPT_Wpedantic, + "ISO C does not support complex integer types"); + specs->type = build_complex_type (specs->type); + } + break; + case cts_int: + gcc_assert (!(specs->long_p && specs->short_p)); + gcc_assert (!(specs->signed_p && specs->unsigned_p)); + if (specs->long_long_p) + specs->type = (specs->unsigned_p + ? long_long_unsigned_type_node + : long_long_integer_type_node); + else if (specs->long_p) + specs->type = (specs->unsigned_p + ? long_unsigned_type_node + : long_integer_type_node); + else if (specs->short_p) + specs->type = (specs->unsigned_p + ? short_unsigned_type_node + : short_integer_type_node); + else + specs->type = (specs->unsigned_p + ? unsigned_type_node + : integer_type_node); + if (specs->complex_p) + { + pedwarn (specs->locations[cdw_complex], OPT_Wpedantic, + "ISO C does not support complex integer types"); + specs->type = build_complex_type (specs->type); + } + break; + case cts_float: + gcc_assert (!specs->long_p && !specs->short_p + && !specs->signed_p && !specs->unsigned_p); + specs->type = (specs->complex_p + ? complex_float_type_node + : float_type_node); + break; + case cts_double: + gcc_assert (!specs->long_long_p && !specs->short_p + && !specs->signed_p && !specs->unsigned_p); + if (specs->long_p) + { + specs->type = (specs->complex_p + ? complex_long_double_type_node + : long_double_type_node); + } + else + { + specs->type = (specs->complex_p + ? complex_double_type_node + : double_type_node); + } + break; + case cts_dfloat32: + case cts_dfloat64: + case cts_dfloat128: + gcc_assert (!specs->long_p && !specs->long_long_p && !specs->short_p + && !specs->signed_p && !specs->unsigned_p && !specs->complex_p); + if (specs->typespec_word == cts_dfloat32) + specs->type = dfloat32_type_node; + else if (specs->typespec_word == cts_dfloat64) + specs->type = dfloat64_type_node; + else + specs->type = dfloat128_type_node; + break; + case cts_fract: + gcc_assert (!specs->complex_p); + if (!targetm.fixed_point_supported_p ()) + specs->type = integer_type_node; + else if (specs->saturating_p) + { + if (specs->long_long_p) + specs->type = specs->unsigned_p + ? sat_unsigned_long_long_fract_type_node + : sat_long_long_fract_type_node; + else if (specs->long_p) + specs->type = specs->unsigned_p + ? sat_unsigned_long_fract_type_node + : sat_long_fract_type_node; + else if (specs->short_p) + specs->type = specs->unsigned_p + ? sat_unsigned_short_fract_type_node + : sat_short_fract_type_node; + else + specs->type = specs->unsigned_p + ? sat_unsigned_fract_type_node + : sat_fract_type_node; + } + else + { + if (specs->long_long_p) + specs->type = specs->unsigned_p + ? unsigned_long_long_fract_type_node + : long_long_fract_type_node; + else if (specs->long_p) + specs->type = specs->unsigned_p + ? unsigned_long_fract_type_node + : long_fract_type_node; + else if (specs->short_p) + specs->type = specs->unsigned_p + ? unsigned_short_fract_type_node + : short_fract_type_node; + else + specs->type = specs->unsigned_p + ? unsigned_fract_type_node + : fract_type_node; + } + break; + case cts_accum: + gcc_assert (!specs->complex_p); + if (!targetm.fixed_point_supported_p ()) + specs->type = integer_type_node; + else if (specs->saturating_p) + { + if (specs->long_long_p) + specs->type = specs->unsigned_p + ? sat_unsigned_long_long_accum_type_node + : sat_long_long_accum_type_node; + else if (specs->long_p) + specs->type = specs->unsigned_p + ? sat_unsigned_long_accum_type_node + : sat_long_accum_type_node; + else if (specs->short_p) + specs->type = specs->unsigned_p + ? sat_unsigned_short_accum_type_node + : sat_short_accum_type_node; + else + specs->type = specs->unsigned_p + ? sat_unsigned_accum_type_node + : sat_accum_type_node; + } + else + { + if (specs->long_long_p) + specs->type = specs->unsigned_p + ? unsigned_long_long_accum_type_node + : long_long_accum_type_node; + else if (specs->long_p) + specs->type = specs->unsigned_p + ? unsigned_long_accum_type_node + : long_accum_type_node; + else if (specs->short_p) + specs->type = specs->unsigned_p + ? unsigned_short_accum_type_node + : short_accum_type_node; + else + specs->type = specs->unsigned_p + ? unsigned_accum_type_node + : accum_type_node; + } + break; + default: + gcc_unreachable (); + } + + return specs; +} + +/* A subroutine of c_write_global_declarations. Perform final processing + on one file scope's declarations (or the external scope's declarations), + GLOBALS. */ + +static void +c_write_global_declarations_1 (tree globals) +{ + tree decl; + bool reconsider; + + /* Process the decls in the order they were written. */ + for (decl = globals; decl; decl = DECL_CHAIN (decl)) + { + /* Check for used but undefined static functions using the C + standard's definition of "used", and set TREE_NO_WARNING so + that check_global_declarations doesn't repeat the check. */ + if (TREE_CODE (decl) == FUNCTION_DECL + && DECL_INITIAL (decl) == 0 + && DECL_EXTERNAL (decl) + && !TREE_PUBLIC (decl) + && C_DECL_USED (decl)) + { + pedwarn (input_location, 0, "%q+F used but never defined", decl); + TREE_NO_WARNING (decl) = 1; + } + + wrapup_global_declaration_1 (decl); + } + + do + { + reconsider = false; + for (decl = globals; decl; decl = DECL_CHAIN (decl)) + reconsider |= wrapup_global_declaration_2 (decl); + } + while (reconsider); + + for (decl = globals; decl; decl = DECL_CHAIN (decl)) + check_global_declaration_1 (decl); +} + +/* A subroutine of c_write_global_declarations Emit debug information for each + of the declarations in GLOBALS. */ + +static void +c_write_global_declarations_2 (tree globals) +{ + tree decl; + + for (decl = globals; decl ; decl = DECL_CHAIN (decl)) + debug_hooks->global_decl (decl); +} + +/* Callback to collect a source_ref from a DECL. */ + +static void +collect_source_ref_cb (tree decl) +{ + if (!DECL_IS_BUILTIN (decl)) + collect_source_ref (LOCATION_FILE (decl_sloc (decl, false))); +} + +/* Preserve the external declarations scope across a garbage collect. */ +static GTY(()) tree ext_block; + +/* Collect all references relevant to SOURCE_FILE. */ + +static void +collect_all_refs (const char *source_file) +{ + tree t; + unsigned i; + + FOR_EACH_VEC_ELT (tree, all_translation_units, i, t) + collect_ada_nodes (BLOCK_VARS (DECL_INITIAL (t)), source_file); + + collect_ada_nodes (BLOCK_VARS (ext_block), source_file); +} + +/* Iterate over all global declarations and call CALLBACK. */ + +static void +for_each_global_decl (void (*callback) (tree decl)) +{ + tree t; + tree decls; + tree decl; + unsigned i; + + FOR_EACH_VEC_ELT (tree, all_translation_units, i, t) + { + decls = DECL_INITIAL (t); + for (decl = BLOCK_VARS (decls); decl; decl = TREE_CHAIN (decl)) + callback (decl); + } + + for (decl = BLOCK_VARS (ext_block); decl; decl = TREE_CHAIN (decl)) + callback (decl); +} + +void +c_write_global_declarations (void) +{ + tree t; + unsigned i; + + /* We don't want to do this if generating a PCH. */ + if (pch_file) + return; + + timevar_start (TV_PHASE_DEFERRED); + + /* Do the Objective-C stuff. This is where all the Objective-C + module stuff gets generated (symtab, class/protocol/selector + lists etc). */ + if (c_dialect_objc ()) + objc_write_global_declarations (); + + /* Close the external scope. */ + ext_block = pop_scope (); + external_scope = 0; + gcc_assert (!current_scope); + + /* Handle -fdump-ada-spec[-slim]. */ + if (dump_enabled_p (TDI_ada)) + { + /* Build a table of files to generate specs for */ + if (get_dump_file_info (TDI_ada)->flags & TDF_SLIM) + collect_source_ref (main_input_filename); + else + for_each_global_decl (collect_source_ref_cb); + + dump_ada_specs (collect_all_refs, NULL); + } + + if (ext_block) + { + tree tmp = BLOCK_VARS (ext_block); + int flags; + FILE * stream = dump_begin (TDI_tu, &flags); + if (stream && tmp) + { + dump_node (tmp, flags & ~TDF_SLIM, stream); + dump_end (TDI_tu, stream); + } + } + + /* Process all file scopes in this compilation, and the external_scope, + through wrapup_global_declarations and check_global_declarations. */ + FOR_EACH_VEC_ELT (tree, all_translation_units, i, t) + c_write_global_declarations_1 (BLOCK_VARS (DECL_INITIAL (t))); + c_write_global_declarations_1 (BLOCK_VARS (ext_block)); + + timevar_stop (TV_PHASE_DEFERRED); + timevar_start (TV_PHASE_OPT_GEN); + + /* We're done parsing; proceed to optimize and emit assembly. + FIXME: shouldn't be the front end's responsibility to call this. */ + finalize_compilation_unit (); + + timevar_stop (TV_PHASE_OPT_GEN); + timevar_start (TV_PHASE_DBGINFO); + + /* After cgraph has had a chance to emit everything that's going to + be emitted, output debug information for globals. */ + if (!seen_error ()) + { + timevar_push (TV_SYMOUT); + FOR_EACH_VEC_ELT (tree, all_translation_units, i, t) + c_write_global_declarations_2 (BLOCK_VARS (DECL_INITIAL (t))); + c_write_global_declarations_2 (BLOCK_VARS (ext_block)); + timevar_pop (TV_SYMOUT); + } + + ext_block = NULL; + timevar_stop (TV_PHASE_DBGINFO); +} + +/* Register reserved keyword WORD as qualifier for address space AS. */ + +void +c_register_addr_space (const char *word, addr_space_t as) +{ + int rid = RID_FIRST_ADDR_SPACE + as; + tree id; + + /* Address space qualifiers are only supported + in C with GNU extensions enabled. */ + if (c_dialect_objc () || flag_no_asm) + return; + + id = get_identifier (word); + C_SET_RID_CODE (id, rid); + C_IS_RESERVED_WORD (id) = 1; + ridpointers [rid] = id; +} + +#include "gt-c-c-decl.h" diff --git a/gcc/c/c-errors.c b/gcc/c/c-errors.c new file mode 100644 index 00000000000..bee534c44fe --- /dev/null +++ b/gcc/c/c-errors.c @@ -0,0 +1,64 @@ +/* Various diagnostic subroutines for the GNU C language. + Copyright (C) 2000, 2001, 2003, 2007, 2008 Free Software Foundation, Inc. + Contributed by Gabriel Dos Reis <gdr@codesourcery.com> + +This file is part of GCC. + +GCC 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 3, or (at your option) any later +version. + +GCC 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 GCC; see the file COPYING3. If not see +<http://www.gnu.org/licenses/>. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "tm.h" +#include "tree.h" +#include "c-tree.h" +#include "tm_p.h" +#include "flags.h" +#include "diagnostic.h" + +/* Issue an ISO C99 pedantic warning MSGID. */ + +void +pedwarn_c99 (location_t location, int opt, const char *gmsgid, ...) +{ + diagnostic_info diagnostic; + va_list ap; + + va_start (ap, gmsgid); + diagnostic_set_info (&diagnostic, gmsgid, &ap, location, + flag_isoc99 ? DK_PEDWARN : DK_WARNING); + diagnostic.option_index = opt; + report_diagnostic (&diagnostic); + va_end (ap); +} + +/* Issue an ISO C90 pedantic warning MSGID. This function is supposed to + be used for matters that are allowed in ISO C99 but not supported in + ISO C90, thus we explicitly don't pedwarn when C99 is specified. + (There is no flag_c90.) */ + +void +pedwarn_c90 (location_t location, int opt, const char *gmsgid, ...) +{ + diagnostic_info diagnostic; + va_list ap; + + va_start (ap, gmsgid); + diagnostic_set_info (&diagnostic, gmsgid, &ap, location, + flag_isoc99 ? DK_WARNING : DK_PEDWARN); + diagnostic.option_index = opt; + report_diagnostic (&diagnostic); + va_end (ap); +} diff --git a/gcc/c/c-lang.c b/gcc/c/c-lang.c new file mode 100644 index 00000000000..ae1b08139e7 --- /dev/null +++ b/gcc/c/c-lang.c @@ -0,0 +1,52 @@ +/* Language-specific hook definitions for C front end. + Copyright (C) 1991, 1995, 1997, 1998, + 1999, 2000, 2001, 2003, 2004, 2005, 2007, 2008, 2009, 2010 + Free Software Foundation, Inc. + +This file is part of GCC. + +GCC 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 3, or (at your option) any later +version. + +GCC 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 GCC; see the file COPYING3. If not see +<http://www.gnu.org/licenses/>. */ + + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "tm.h" +#include "tree.h" +#include "c-tree.h" +#include "c-family/c-common.h" +#include "langhooks.h" +#include "langhooks-def.h" +#include "tree-inline.h" +#include "diagnostic-core.h" +#include "c-objc-common.h" +#include "c-family/c-pragma.h" + +enum c_language_kind c_language = clk_c; + +/* Lang hooks common to C and ObjC are declared in c-objc-common.h; + consequently, there should be very few hooks below. */ + +#undef LANG_HOOKS_NAME +#define LANG_HOOKS_NAME "GNU C" +#undef LANG_HOOKS_INIT +#define LANG_HOOKS_INIT c_objc_common_init +#undef LANG_HOOKS_INIT_TS +#define LANG_HOOKS_INIT_TS c_common_init_ts + +/* Each front end provides its own lang hook initializer. */ +struct lang_hooks lang_hooks = LANG_HOOKS_INITIALIZER; + +#include "gtype-c.h" diff --git a/gcc/c/c-lang.h b/gcc/c/c-lang.h new file mode 100644 index 00000000000..256a269fe0b --- /dev/null +++ b/gcc/c/c-lang.h @@ -0,0 +1,60 @@ +/* Definitions for C language specific types. + Copyright (C) 2009, 2010 + Free Software Foundation, Inc. + +This file is part of GCC. + +GCC 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 3, or (at your option) any later +version. + +GCC 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 GCC; see the file COPYING3. If not see +<http://www.gnu.org/licenses/>. */ + +#ifndef GCC_C_LANG_H +#define GCC_C_LANG_H + +#include "c-family/c-common.h" +#include "ggc.h" + +struct GTY((variable_size)) lang_type { + /* In a RECORD_TYPE, a sorted array of the fields of the type. */ + struct sorted_fields_type * GTY ((reorder ("resort_sorted_fields"))) s; + /* In an ENUMERAL_TYPE, the min and max values. */ + tree enum_min; + tree enum_max; + /* In a RECORD_TYPE, information specific to Objective-C, such + as a list of adopted protocols or a pointer to a corresponding + @interface. See objc/objc-act.h for details. */ + tree objc_info; +}; + +struct GTY(()) lang_decl { + char dummy; +}; + +/* 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 GTY(()) language_function { + struct c_language_function base; + tree x_break_label; + tree x_cont_label; + struct c_switch * GTY((skip)) x_switch_stack; + struct c_arg_info * GTY((skip)) arg_info; + int returns_value; + int returns_null; + int returns_abnormally; + int warn_about_return_type; +}; + + +#endif /* ! GCC_C_LANG_H */ diff --git a/gcc/c/c-objc-common.c b/gcc/c/c-objc-common.c new file mode 100644 index 00000000000..9351cd5a539 --- /dev/null +++ b/gcc/c/c-objc-common.c @@ -0,0 +1,214 @@ +/* Some code common to C and ObjC front ends. + Copyright (C) 2001, 2002, 2003, 2004, 2005, 2007, + 2009, 2010 Free Software Foundation, Inc. + +This file is part of GCC. + +GCC 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 3, or (at your option) any later +version. + +GCC 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 GCC; see the file COPYING3. If not see +<http://www.gnu.org/licenses/>. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "tree.h" +#include "c-tree.h" +#include "intl.h" +#include "c-family/c-pretty-print.h" +#include "flags.h" +#include "diagnostic.h" +#include "tree-pretty-print.h" +#include "langhooks.h" +#include "c-objc-common.h" + +static bool c_tree_printer (pretty_printer *, text_info *, const char *, + int, bool, bool, bool); + +bool +c_missing_noreturn_ok_p (tree decl) +{ + /* A missing noreturn is not ok for freestanding implementations and + ok for the `main' function in hosted implementations. */ + return flag_hosted && MAIN_NAME_P (DECL_ASSEMBLER_NAME (decl)); +} + +/* Called from check_global_declarations. */ + +bool +c_warn_unused_global_decl (const_tree decl) +{ + if (TREE_CODE (decl) == FUNCTION_DECL && DECL_DECLARED_INLINE_P (decl)) + return false; + if (DECL_IN_SYSTEM_HEADER (decl)) + return false; + + return true; +} + +/* Initialization common to C and Objective-C front ends. */ +bool +c_objc_common_init (void) +{ + c_init_decl_processing (); + + if (c_common_init () == false) + return false; + + /* These were not defined in the Objective-C front end, but I'm + putting them here anyway. The diagnostic format decoder might + want an enhanced ObjC implementation. */ + diagnostic_format_decoder (global_dc) = &c_tree_printer; + + return true; +} + +/* Called during diagnostic message formatting process to print a + source-level entity onto BUFFER. The meaning of the format specifiers + is as follows: + %D: a general decl, + %E: an identifier or expression, + %F: a function declaration, + %T: a type. + %V: a list of type qualifiers from a tree. + %v: an explicit list of type qualifiers + %#v: an explicit list of type qualifiers of a function type. + + Please notice when called, the `%' part was already skipped by the + diagnostic machinery. */ +static bool +c_tree_printer (pretty_printer *pp, text_info *text, const char *spec, + int precision, bool wide, bool set_locus, bool hash) +{ + tree t = NULL_TREE; + tree name; + c_pretty_printer *cpp = (c_pretty_printer *) pp; + pp->padding = pp_none; + + if (precision != 0 || wide) + return false; + + if (*spec == 'K') + { + percent_K_format (text); + return true; + } + + if (*spec != 'v') + { + t = va_arg (*text->args_ptr, tree); + if (set_locus && text->locus) + *text->locus = DECL_SOURCE_LOCATION (t); + } + + switch (*spec) + { + case 'D': + if (DECL_DEBUG_EXPR_IS_FROM (t) && DECL_DEBUG_EXPR (t)) + { + t = DECL_DEBUG_EXPR (t); + if (!DECL_P (t)) + { + pp_c_expression (cpp, t); + return true; + } + } + /* FALLTHRU */ + + case 'F': + if (DECL_NAME (t)) + { + pp_identifier (cpp, lang_hooks.decl_printable_name (t, 2)); + return true; + } + break; + + case 'T': + gcc_assert (TYPE_P (t)); + name = TYPE_NAME (t); + + if (name && TREE_CODE (name) == TYPE_DECL) + { + if (DECL_NAME (name)) + pp_identifier (cpp, lang_hooks.decl_printable_name (name, 2)); + else + pp_type_id (cpp, t); + return true; + } + else + { + pp_type_id (cpp, t); + return true; + } + break; + + case 'E': + if (TREE_CODE (t) == IDENTIFIER_NODE) + pp_identifier (cpp, IDENTIFIER_POINTER (t)); + else + pp_expression (cpp, t); + return true; + + case 'V': + pp_c_type_qualifier_list (cpp, t); + return true; + + case 'v': + pp_c_cv_qualifiers (cpp, va_arg (*text->args_ptr, int), hash); + return true; + + default: + return false; + } + + pp_string (cpp, _("({anonymous})")); + return true; +} + +/* In C and ObjC, all decls have "C" linkage. */ +bool +has_c_linkage (const_tree decl ATTRIBUTE_UNUSED) +{ + return true; +} + +void +c_initialize_diagnostics (diagnostic_context *context) +{ + pretty_printer *base; + c_pretty_printer *pp; + + c_common_initialize_diagnostics (context); + + base = context->printer; + pp = XNEW (c_pretty_printer); + memcpy (pp_base (pp), base, sizeof (pretty_printer)); + pp_c_pretty_printer_init (pp); + context->printer = (pretty_printer *) pp; + + /* It is safe to free this object because it was previously XNEW()'d. */ + XDELETE (base); +} + +int +c_types_compatible_p (tree x, tree y) +{ + return comptypes (TYPE_MAIN_VARIANT (x), TYPE_MAIN_VARIANT (y)); +} + +/* Determine if the type is a vla type for the backend. */ + +bool +c_vla_unspec_p (tree x, tree fn ATTRIBUTE_UNUSED) +{ + return c_vla_type_p (x); +} diff --git a/gcc/c/c-objc-common.h b/gcc/c/c-objc-common.h new file mode 100644 index 00000000000..dbbd50a729d --- /dev/null +++ b/gcc/c/c-objc-common.h @@ -0,0 +1,109 @@ +/* Language hooks common to C and ObjC front ends. + Copyright (C) 2004, 2005, 2007, 2008, 2009, 2010 + Free Software Foundation, Inc. + Contributed by Ziemowit Laski <zlaski@apple.com> + +This file is part of GCC. + +GCC 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 3, or (at your option) any later +version. + +GCC 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 GCC; see the file COPYING3. If not see +<http://www.gnu.org/licenses/>. */ + +#ifndef GCC_C_OBJC_COMMON +#define GCC_C_OBJC_COMMON + +/* Lang hooks that are shared between C and ObjC are defined here. Hooks + specific to C or ObjC go in c-lang.c and objc/objc-lang.c, respectively. */ + +#undef LANG_HOOKS_IDENTIFIER_SIZE +#define LANG_HOOKS_IDENTIFIER_SIZE C_SIZEOF_STRUCT_LANG_IDENTIFIER +#undef LANG_HOOKS_FINISH +#define LANG_HOOKS_FINISH c_common_finish +#undef LANG_HOOKS_OPTION_LANG_MASK +#define LANG_HOOKS_OPTION_LANG_MASK c_common_option_lang_mask +#undef LANG_HOOKS_COMPLAIN_WRONG_LANG_P +#define LANG_HOOKS_COMPLAIN_WRONG_LANG_P c_common_complain_wrong_lang_p +#undef LANG_HOOKS_INIT_OPTIONS_STRUCT +#define LANG_HOOKS_INIT_OPTIONS_STRUCT c_common_init_options_struct +#undef LANG_HOOKS_INIT_OPTIONS +#define LANG_HOOKS_INIT_OPTIONS c_common_init_options +#undef LANG_HOOKS_INITIALIZE_DIAGNOSTICS +#define LANG_HOOKS_INITIALIZE_DIAGNOSTICS c_initialize_diagnostics +#undef LANG_HOOKS_HANDLE_OPTION +#define LANG_HOOKS_HANDLE_OPTION c_common_handle_option +#undef LANG_HOOKS_POST_OPTIONS +#define LANG_HOOKS_POST_OPTIONS c_common_post_options +#undef LANG_HOOKS_GET_ALIAS_SET +#define LANG_HOOKS_GET_ALIAS_SET c_common_get_alias_set +#undef LANG_HOOKS_PARSE_FILE +#define LANG_HOOKS_PARSE_FILE c_common_parse_file +#undef LANG_HOOKS_FINISH_INCOMPLETE_DECL +#define LANG_HOOKS_FINISH_INCOMPLETE_DECL c_finish_incomplete_decl +#undef LANG_HOOKS_WARN_UNUSED_GLOBAL_DECL +#define LANG_HOOKS_WARN_UNUSED_GLOBAL_DECL c_warn_unused_global_decl +#undef LANG_HOOKS_PRINT_IDENTIFIER +#define LANG_HOOKS_PRINT_IDENTIFIER c_print_identifier +#undef LANG_HOOKS_TYPES_COMPATIBLE_P +#define LANG_HOOKS_TYPES_COMPATIBLE_P c_types_compatible_p +#undef LANG_HOOKS_MISSING_NORETURN_OK_P +#define LANG_HOOKS_MISSING_NORETURN_OK_P c_missing_noreturn_ok_p +#undef LANG_HOOKS_BUILTIN_FUNCTION +#define LANG_HOOKS_BUILTIN_FUNCTION c_builtin_function +#undef LANG_HOOKS_BUILTIN_FUNCTION_EXT_SCOPE +#define LANG_HOOKS_BUILTIN_FUNCTION_EXT_SCOPE c_builtin_function_ext_scope + +/* Attribute hooks. */ +#undef LANG_HOOKS_COMMON_ATTRIBUTE_TABLE +#define LANG_HOOKS_COMMON_ATTRIBUTE_TABLE c_common_attribute_table +#undef LANG_HOOKS_FORMAT_ATTRIBUTE_TABLE +#define LANG_HOOKS_FORMAT_ATTRIBUTE_TABLE c_common_format_attribute_table + +#undef LANG_HOOKS_TREE_DUMP_DUMP_TREE_FN +#define LANG_HOOKS_TREE_DUMP_DUMP_TREE_FN c_dump_tree + +#undef LANG_HOOKS_TYPE_FOR_MODE +#define LANG_HOOKS_TYPE_FOR_MODE c_common_type_for_mode +#undef LANG_HOOKS_TYPE_FOR_SIZE +#define LANG_HOOKS_TYPE_FOR_SIZE c_common_type_for_size +#undef LANG_HOOKS_INCOMPLETE_TYPE_ERROR +#define LANG_HOOKS_INCOMPLETE_TYPE_ERROR c_incomplete_type_error +#undef LANG_HOOKS_TYPE_PROMOTES_TO +#define LANG_HOOKS_TYPE_PROMOTES_TO c_type_promotes_to +#undef LANG_HOOKS_REGISTER_BUILTIN_TYPE +#define LANG_HOOKS_REGISTER_BUILTIN_TYPE c_register_builtin_type +#undef LANG_HOOKS_TO_TARGET_CHARSET +#define LANG_HOOKS_TO_TARGET_CHARSET c_common_to_target_charset +#undef LANG_HOOKS_EXPR_TO_DECL +#define LANG_HOOKS_EXPR_TO_DECL c_expr_to_decl + +/* The C front end's scoping structure is very different from + that expected by the language-independent code; it is best + to disable getdecls. + This means it must also provide its own write_globals. */ + +#undef LANG_HOOKS_GETDECLS +#define LANG_HOOKS_GETDECLS lhd_return_null_tree_v +#undef LANG_HOOKS_WRITE_GLOBALS +#define LANG_HOOKS_WRITE_GLOBALS c_write_global_declarations + +/* Hooks for tree gimplification. */ +#undef LANG_HOOKS_GIMPLIFY_EXPR +#define LANG_HOOKS_GIMPLIFY_EXPR c_gimplify_expr + +#undef LANG_HOOKS_OMP_PREDETERMINED_SHARING +#define LANG_HOOKS_OMP_PREDETERMINED_SHARING c_omp_predetermined_sharing + +#undef LANG_HOOKS_TREE_INLINING_VAR_MOD_TYPE_P +#define LANG_HOOKS_TREE_INLINING_VAR_MOD_TYPE_P c_vla_unspec_p + +#endif /* GCC_C_OBJC_COMMON */ diff --git a/gcc/c/c-parser.c b/gcc/c/c-parser.c new file mode 100644 index 00000000000..2237749e4a3 --- /dev/null +++ b/gcc/c/c-parser.c @@ -0,0 +1,10840 @@ +/* Parser for C and Objective-C. + Copyright (C) 1987, 1988, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998, + 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2007, 2008, 2009, 2010, 2011, + 2012 Free Software Foundation, Inc. + + Parser actions based on the old Bison parser; structure somewhat + influenced by and fragments based on the C++ parser. + +This file is part of GCC. + +GCC 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 3, or (at your option) any later +version. + +GCC 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 GCC; see the file COPYING3. If not see +<http://www.gnu.org/licenses/>. */ + +/* TODO: + + Make sure all relevant comments, and all relevant code from all + actions, brought over from old parser. Verify exact correspondence + of syntax accepted. + + Add testcases covering every input symbol in every state in old and + new parsers. + + Include full syntax for GNU C, including erroneous cases accepted + with error messages, in syntax productions in comments. + + Make more diagnostics in the front end generally take an explicit + location rather than implicitly using input_location. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "tm.h" /* For rtl.h: needs enum reg_class. */ +#include "tree.h" +#include "langhooks.h" +#include "input.h" +#include "cpplib.h" +#include "timevar.h" +#include "c-family/c-pragma.h" +#include "c-tree.h" +#include "flags.h" +#include "ggc.h" +#include "c-family/c-common.h" +#include "c-family/c-objc.h" +#include "vec.h" +#include "target.h" +#include "cgraph.h" +#include "plugin.h" + + +/* Initialization routine for this file. */ + +void +c_parse_init (void) +{ + /* The only initialization required is of the reserved word + identifiers. */ + unsigned int i; + tree id; + int mask = 0; + + /* Make sure RID_MAX hasn't grown past the 8 bits used to hold the keyword in + the c_token structure. */ + gcc_assert (RID_MAX <= 255); + + mask |= D_CXXONLY; + if (!flag_isoc99) + mask |= D_C99; + if (flag_no_asm) + { + mask |= D_ASM | D_EXT; + if (!flag_isoc99) + mask |= D_EXT89; + } + if (!c_dialect_objc ()) + mask |= D_OBJC | D_CXX_OBJC; + + ridpointers = ggc_alloc_cleared_vec_tree ((int) RID_MAX); + for (i = 0; i < num_c_common_reswords; i++) + { + /* If a keyword is disabled, do not enter it into the table + and so create a canonical spelling that isn't a keyword. */ + if (c_common_reswords[i].disable & mask) + { + if (warn_cxx_compat + && (c_common_reswords[i].disable & D_CXXWARN)) + { + id = get_identifier (c_common_reswords[i].word); + C_SET_RID_CODE (id, RID_CXX_COMPAT_WARN); + C_IS_RESERVED_WORD (id) = 1; + } + continue; + } + + id = get_identifier (c_common_reswords[i].word); + C_SET_RID_CODE (id, c_common_reswords[i].rid); + C_IS_RESERVED_WORD (id) = 1; + ridpointers [(int) c_common_reswords[i].rid] = id; + } +} + +/* The C lexer intermediates between the lexer in cpplib and c-lex.c + and the C parser. Unlike the C++ lexer, the parser structure + stores the lexer information instead of using a separate structure. + Identifiers are separated into ordinary identifiers, type names, + keywords and some other Objective-C types of identifiers, and some + look-ahead is maintained. + + ??? It might be a good idea to lex the whole file up front (as for + C++). It would then be possible to share more of the C and C++ + lexer code, if desired. */ + +/* The following local token type is used. */ + +/* A keyword. */ +#define CPP_KEYWORD ((enum cpp_ttype) (N_TTYPES + 1)) + +/* More information about the type of a CPP_NAME token. */ +typedef enum c_id_kind { + /* An ordinary identifier. */ + C_ID_ID, + /* An identifier declared as a typedef name. */ + C_ID_TYPENAME, + /* An identifier declared as an Objective-C class name. */ + C_ID_CLASSNAME, + /* An address space identifier. */ + C_ID_ADDRSPACE, + /* Not an identifier. */ + C_ID_NONE +} c_id_kind; + +/* A single C token after string literal concatenation and conversion + of preprocessing tokens to tokens. */ +typedef struct GTY (()) c_token { + /* The kind of token. */ + ENUM_BITFIELD (cpp_ttype) type : 8; + /* If this token is a CPP_NAME, this value indicates whether also + declared as some kind of type. Otherwise, it is C_ID_NONE. */ + ENUM_BITFIELD (c_id_kind) id_kind : 8; + /* If this token is a keyword, this value indicates which keyword. + Otherwise, this value is RID_MAX. */ + ENUM_BITFIELD (rid) keyword : 8; + /* If this token is a CPP_PRAGMA, this indicates the pragma that + was seen. Otherwise it is PRAGMA_NONE. */ + ENUM_BITFIELD (pragma_kind) pragma_kind : 8; + /* The location at which this token was found. */ + location_t location; + /* The value associated with this token, if any. */ + tree value; +} c_token; + +/* A parser structure recording information about the state and + context of parsing. Includes lexer information with up to two + tokens of look-ahead; more are not needed for C. */ +typedef struct GTY(()) c_parser { + /* The look-ahead tokens. */ + c_token tokens[2]; + /* How many look-ahead tokens are available (0, 1 or 2). */ + short tokens_avail; + /* True if a syntax error is being recovered from; false otherwise. + c_parser_error sets this flag. It should clear this flag when + enough tokens have been consumed to recover from the error. */ + BOOL_BITFIELD error : 1; + /* True if we're processing a pragma, and shouldn't automatically + consume CPP_PRAGMA_EOL. */ + BOOL_BITFIELD in_pragma : 1; + /* True if we're parsing the outermost block of an if statement. */ + BOOL_BITFIELD in_if_block : 1; + /* True if we want to lex an untranslated string. */ + BOOL_BITFIELD lex_untranslated_string : 1; + + /* Objective-C specific parser/lexer information. */ + + /* True if we are in a context where the Objective-C "PQ" keywords + are considered keywords. */ + BOOL_BITFIELD objc_pq_context : 1; + /* True if we are parsing a (potential) Objective-C foreach + statement. This is set to true after we parsed 'for (' and while + we wait for 'in' or ';' to decide if it's a standard C for loop or an + Objective-C foreach loop. */ + BOOL_BITFIELD objc_could_be_foreach_context : 1; + /* The following flag is needed to contextualize Objective-C lexical + analysis. In some cases (e.g., 'int NSObject;'), it is + undesirable to bind an identifier to an Objective-C class, even + if a class with that name exists. */ + BOOL_BITFIELD objc_need_raw_identifier : 1; + /* Nonzero if we're processing a __transaction statement. The value + is 1 | TM_STMT_ATTR_*. */ + unsigned int in_transaction : 4; + /* True if we are in a context where the Objective-C "Property attribute" + keywords are valid. */ + BOOL_BITFIELD objc_property_attr_context : 1; +} c_parser; + + +/* The actual parser and external interface. ??? Does this need to be + garbage-collected? */ + +static GTY (()) c_parser *the_parser; + +/* Read in and lex a single token, storing it in *TOKEN. */ + +static void +c_lex_one_token (c_parser *parser, c_token *token) +{ + timevar_push (TV_LEX); + + token->type = c_lex_with_flags (&token->value, &token->location, NULL, + (parser->lex_untranslated_string + ? C_LEX_STRING_NO_TRANSLATE : 0)); + token->id_kind = C_ID_NONE; + token->keyword = RID_MAX; + token->pragma_kind = PRAGMA_NONE; + + switch (token->type) + { + case CPP_NAME: + { + tree decl; + + bool objc_force_identifier = parser->objc_need_raw_identifier; + if (c_dialect_objc ()) + parser->objc_need_raw_identifier = false; + + if (C_IS_RESERVED_WORD (token->value)) + { + enum rid rid_code = C_RID_CODE (token->value); + + if (rid_code == RID_CXX_COMPAT_WARN) + { + warning_at (token->location, + OPT_Wc___compat, + "identifier %qE conflicts with C++ keyword", + token->value); + } + else if (rid_code >= RID_FIRST_ADDR_SPACE + && rid_code <= RID_LAST_ADDR_SPACE) + { + token->id_kind = C_ID_ADDRSPACE; + token->keyword = rid_code; + break; + } + else if (c_dialect_objc () && OBJC_IS_PQ_KEYWORD (rid_code)) + { + /* We found an Objective-C "pq" keyword (in, out, + inout, bycopy, byref, oneway). They need special + care because the interpretation depends on the + context. */ + if (parser->objc_pq_context) + { + token->type = CPP_KEYWORD; + token->keyword = rid_code; + break; + } + else if (parser->objc_could_be_foreach_context + && rid_code == RID_IN) + { + /* We are in Objective-C, inside a (potential) + foreach context (which means after having + parsed 'for (', but before having parsed ';'), + and we found 'in'. We consider it the keyword + which terminates the declaration at the + beginning of a foreach-statement. Note that + this means you can't use 'in' for anything else + in that context; in particular, in Objective-C + you can't use 'in' as the name of the running + variable in a C for loop. We could potentially + try to add code here to disambiguate, but it + seems a reasonable limitation. */ + token->type = CPP_KEYWORD; + token->keyword = rid_code; + break; + } + /* Else, "pq" keywords outside of the "pq" context are + not keywords, and we fall through to the code for + normal tokens. */ + } + else if (c_dialect_objc () && OBJC_IS_PATTR_KEYWORD (rid_code)) + { + /* We found an Objective-C "property attribute" + keyword (getter, setter, readonly, etc). These are + only valid in the property context. */ + if (parser->objc_property_attr_context) + { + token->type = CPP_KEYWORD; + token->keyword = rid_code; + break; + } + /* Else they are not special keywords. + */ + } + else if (c_dialect_objc () + && (OBJC_IS_AT_KEYWORD (rid_code) + || OBJC_IS_CXX_KEYWORD (rid_code))) + { + /* We found one of the Objective-C "@" keywords (defs, + selector, synchronized, etc) or one of the + Objective-C "cxx" keywords (class, private, + protected, public, try, catch, throw) without a + preceding '@' sign. Do nothing and fall through to + the code for normal tokens (in C++ we would still + consider the CXX ones keywords, but not in C). */ + ; + } + else + { + token->type = CPP_KEYWORD; + token->keyword = rid_code; + break; + } + } + + decl = lookup_name (token->value); + if (decl) + { + if (TREE_CODE (decl) == TYPE_DECL) + { + token->id_kind = C_ID_TYPENAME; + break; + } + } + else if (c_dialect_objc ()) + { + tree objc_interface_decl = objc_is_class_name (token->value); + /* Objective-C class names are in the same namespace as + variables and typedefs, and hence are shadowed by local + declarations. */ + if (objc_interface_decl + && (!objc_force_identifier || global_bindings_p ())) + { + token->value = objc_interface_decl; + token->id_kind = C_ID_CLASSNAME; + break; + } + } + token->id_kind = C_ID_ID; + } + break; + case CPP_AT_NAME: + /* This only happens in Objective-C; it must be a keyword. */ + token->type = CPP_KEYWORD; + switch (C_RID_CODE (token->value)) + { + /* Replace 'class' with '@class', 'private' with '@private', + etc. This prevents confusion with the C++ keyword + 'class', and makes the tokens consistent with other + Objective-C 'AT' keywords. For example '@class' is + reported as RID_AT_CLASS which is consistent with + '@synchronized', which is reported as + RID_AT_SYNCHRONIZED. + */ + case RID_CLASS: token->keyword = RID_AT_CLASS; break; + case RID_PRIVATE: token->keyword = RID_AT_PRIVATE; break; + case RID_PROTECTED: token->keyword = RID_AT_PROTECTED; break; + case RID_PUBLIC: token->keyword = RID_AT_PUBLIC; break; + case RID_THROW: token->keyword = RID_AT_THROW; break; + case RID_TRY: token->keyword = RID_AT_TRY; break; + case RID_CATCH: token->keyword = RID_AT_CATCH; break; + default: token->keyword = C_RID_CODE (token->value); + } + break; + case CPP_COLON: + case CPP_COMMA: + case CPP_CLOSE_PAREN: + case CPP_SEMICOLON: + /* These tokens may affect the interpretation of any identifiers + following, if doing Objective-C. */ + if (c_dialect_objc ()) + parser->objc_need_raw_identifier = false; + break; + case CPP_PRAGMA: + /* We smuggled the cpp_token->u.pragma value in an INTEGER_CST. */ + token->pragma_kind = (enum pragma_kind) TREE_INT_CST_LOW (token->value); + token->value = NULL; + break; + default: + break; + } + timevar_pop (TV_LEX); +} + +/* Return a pointer to the next token from PARSER, reading it in if + necessary. */ + +static inline c_token * +c_parser_peek_token (c_parser *parser) +{ + if (parser->tokens_avail == 0) + { + c_lex_one_token (parser, &parser->tokens[0]); + parser->tokens_avail = 1; + } + return &parser->tokens[0]; +} + +/* Return true if the next token from PARSER has the indicated + TYPE. */ + +static inline bool +c_parser_next_token_is (c_parser *parser, enum cpp_ttype type) +{ + return c_parser_peek_token (parser)->type == type; +} + +/* Return true if the next token from PARSER does not have the + indicated TYPE. */ + +static inline bool +c_parser_next_token_is_not (c_parser *parser, enum cpp_ttype type) +{ + return !c_parser_next_token_is (parser, type); +} + +/* Return true if the next token from PARSER is the indicated + KEYWORD. */ + +static inline bool +c_parser_next_token_is_keyword (c_parser *parser, enum rid keyword) +{ + return c_parser_peek_token (parser)->keyword == keyword; +} + +/* Return a pointer to the next-but-one token from PARSER, reading it + in if necessary. The next token is already read in. */ + +static c_token * +c_parser_peek_2nd_token (c_parser *parser) +{ + if (parser->tokens_avail >= 2) + return &parser->tokens[1]; + gcc_assert (parser->tokens_avail == 1); + gcc_assert (parser->tokens[0].type != CPP_EOF); + gcc_assert (parser->tokens[0].type != CPP_PRAGMA_EOL); + c_lex_one_token (parser, &parser->tokens[1]); + parser->tokens_avail = 2; + return &parser->tokens[1]; +} + +/* Return true if TOKEN can start a type name, + false otherwise. */ +static bool +c_token_starts_typename (c_token *token) +{ + switch (token->type) + { + case CPP_NAME: + switch (token->id_kind) + { + case C_ID_ID: + return false; + case C_ID_ADDRSPACE: + return true; + case C_ID_TYPENAME: + return true; + case C_ID_CLASSNAME: + gcc_assert (c_dialect_objc ()); + return true; + default: + gcc_unreachable (); + } + case CPP_KEYWORD: + switch (token->keyword) + { + case RID_UNSIGNED: + case RID_LONG: + case RID_INT128: + case RID_SHORT: + case RID_SIGNED: + case RID_COMPLEX: + case RID_INT: + case RID_CHAR: + case RID_FLOAT: + case RID_DOUBLE: + case RID_VOID: + case RID_DFLOAT32: + case RID_DFLOAT64: + case RID_DFLOAT128: + case RID_BOOL: + case RID_ENUM: + case RID_STRUCT: + case RID_UNION: + case RID_TYPEOF: + case RID_CONST: + case RID_VOLATILE: + case RID_RESTRICT: + case RID_ATTRIBUTE: + case RID_FRACT: + case RID_ACCUM: + case RID_SAT: + return true; + default: + return false; + } + case CPP_LESS: + if (c_dialect_objc ()) + return true; + return false; + default: + return false; + } +} + +enum c_lookahead_kind { + /* Always treat unknown identifiers as typenames. */ + cla_prefer_type, + + /* Could be parsing a nonabstract declarator. Only treat an identifier + as a typename if followed by another identifier or a star. */ + cla_nonabstract_decl, + + /* Never treat identifiers as typenames. */ + cla_prefer_id +}; + +/* Return true if the next token from PARSER can start a type name, + false otherwise. LA specifies how to do lookahead in order to + detect unknown type names. If unsure, pick CLA_PREFER_ID. */ + +static inline bool +c_parser_next_tokens_start_typename (c_parser *parser, enum c_lookahead_kind la) +{ + c_token *token = c_parser_peek_token (parser); + if (c_token_starts_typename (token)) + return true; + + /* Try a bit harder to detect an unknown typename. */ + if (la != cla_prefer_id + && token->type == CPP_NAME + && token->id_kind == C_ID_ID + + /* Do not try too hard when we could have "object in array". */ + && !parser->objc_could_be_foreach_context + + && (la == cla_prefer_type + || c_parser_peek_2nd_token (parser)->type == CPP_NAME + || c_parser_peek_2nd_token (parser)->type == CPP_MULT) + + /* Only unknown identifiers. */ + && !lookup_name (token->value)) + return true; + + return false; +} + +/* Return true if TOKEN is a type qualifier, false otherwise. */ +static bool +c_token_is_qualifier (c_token *token) +{ + switch (token->type) + { + case CPP_NAME: + switch (token->id_kind) + { + case C_ID_ADDRSPACE: + return true; + default: + return false; + } + case CPP_KEYWORD: + switch (token->keyword) + { + case RID_CONST: + case RID_VOLATILE: + case RID_RESTRICT: + case RID_ATTRIBUTE: + return true; + default: + return false; + } + case CPP_LESS: + return false; + default: + gcc_unreachable (); + } +} + +/* Return true if the next token from PARSER is a type qualifier, + false otherwise. */ +static inline bool +c_parser_next_token_is_qualifier (c_parser *parser) +{ + c_token *token = c_parser_peek_token (parser); + return c_token_is_qualifier (token); +} + +/* Return true if TOKEN can start declaration specifiers, false + otherwise. */ +static bool +c_token_starts_declspecs (c_token *token) +{ + switch (token->type) + { + case CPP_NAME: + switch (token->id_kind) + { + case C_ID_ID: + return false; + case C_ID_ADDRSPACE: + return true; + case C_ID_TYPENAME: + return true; + case C_ID_CLASSNAME: + gcc_assert (c_dialect_objc ()); + return true; + default: + gcc_unreachable (); + } + case CPP_KEYWORD: + switch (token->keyword) + { + case RID_STATIC: + case RID_EXTERN: + case RID_REGISTER: + case RID_TYPEDEF: + case RID_INLINE: + case RID_NORETURN: + case RID_AUTO: + case RID_THREAD: + case RID_UNSIGNED: + case RID_LONG: + case RID_INT128: + case RID_SHORT: + case RID_SIGNED: + case RID_COMPLEX: + case RID_INT: + case RID_CHAR: + case RID_FLOAT: + case RID_DOUBLE: + case RID_VOID: + case RID_DFLOAT32: + case RID_DFLOAT64: + case RID_DFLOAT128: + case RID_BOOL: + case RID_ENUM: + case RID_STRUCT: + case RID_UNION: + case RID_TYPEOF: + case RID_CONST: + case RID_VOLATILE: + case RID_RESTRICT: + case RID_ATTRIBUTE: + case RID_FRACT: + case RID_ACCUM: + case RID_SAT: + case RID_ALIGNAS: + return true; + default: + return false; + } + case CPP_LESS: + if (c_dialect_objc ()) + return true; + return false; + default: + return false; + } +} + + +/* Return true if TOKEN can start declaration specifiers or a static + assertion, false otherwise. */ +static bool +c_token_starts_declaration (c_token *token) +{ + if (c_token_starts_declspecs (token) + || token->keyword == RID_STATIC_ASSERT) + return true; + else + return false; +} + +/* Return true if the next token from PARSER can start declaration + specifiers, false otherwise. */ +static inline bool +c_parser_next_token_starts_declspecs (c_parser *parser) +{ + c_token *token = c_parser_peek_token (parser); + + /* In Objective-C, a classname normally starts a declspecs unless it + is immediately followed by a dot. In that case, it is the + Objective-C 2.0 "dot-syntax" for class objects, ie, calls the + setter/getter on the class. c_token_starts_declspecs() can't + differentiate between the two cases because it only checks the + current token, so we have a special check here. */ + if (c_dialect_objc () + && token->type == CPP_NAME + && token->id_kind == C_ID_CLASSNAME + && c_parser_peek_2nd_token (parser)->type == CPP_DOT) + return false; + + return c_token_starts_declspecs (token); +} + +/* Return true if the next tokens from PARSER can start declaration + specifiers or a static assertion, false otherwise. */ +static inline bool +c_parser_next_tokens_start_declaration (c_parser *parser) +{ + c_token *token = c_parser_peek_token (parser); + + /* Same as above. */ + if (c_dialect_objc () + && token->type == CPP_NAME + && token->id_kind == C_ID_CLASSNAME + && c_parser_peek_2nd_token (parser)->type == CPP_DOT) + return false; + + /* Labels do not start declarations. */ + if (token->type == CPP_NAME + && c_parser_peek_2nd_token (parser)->type == CPP_COLON) + return false; + + if (c_token_starts_declaration (token)) + return true; + + if (c_parser_next_tokens_start_typename (parser, cla_nonabstract_decl)) + return true; + + return false; +} + +/* Consume the next token from PARSER. */ + +static void +c_parser_consume_token (c_parser *parser) +{ + gcc_assert (parser->tokens_avail >= 1); + gcc_assert (parser->tokens[0].type != CPP_EOF); + gcc_assert (!parser->in_pragma || parser->tokens[0].type != CPP_PRAGMA_EOL); + gcc_assert (parser->error || parser->tokens[0].type != CPP_PRAGMA); + if (parser->tokens_avail == 2) + parser->tokens[0] = parser->tokens[1]; + parser->tokens_avail--; +} + +/* Expect the current token to be a #pragma. Consume it and remember + that we've begun parsing a pragma. */ + +static void +c_parser_consume_pragma (c_parser *parser) +{ + gcc_assert (!parser->in_pragma); + gcc_assert (parser->tokens_avail >= 1); + gcc_assert (parser->tokens[0].type == CPP_PRAGMA); + if (parser->tokens_avail == 2) + parser->tokens[0] = parser->tokens[1]; + parser->tokens_avail--; + parser->in_pragma = true; +} + +/* Update the globals input_location and in_system_header from + TOKEN. */ +static inline void +c_parser_set_source_position_from_token (c_token *token) +{ + if (token->type != CPP_EOF) + { + input_location = token->location; + } +} + +/* Issue a diagnostic of the form + FILE:LINE: MESSAGE before TOKEN + where TOKEN is the next token in the input stream of PARSER. + MESSAGE (specified by the caller) is usually of the form "expected + OTHER-TOKEN". + + Do not issue a diagnostic if still recovering from an error. + + ??? This is taken from the C++ parser, but building up messages in + this way is not i18n-friendly and some other approach should be + used. */ + +static void +c_parser_error (c_parser *parser, const char *gmsgid) +{ + c_token *token = c_parser_peek_token (parser); + if (parser->error) + return; + parser->error = true; + if (!gmsgid) + return; + /* This diagnostic makes more sense if it is tagged to the line of + the token we just peeked at. */ + c_parser_set_source_position_from_token (token); + c_parse_error (gmsgid, + /* Because c_parse_error does not understand + CPP_KEYWORD, keywords are treated like + identifiers. */ + (token->type == CPP_KEYWORD ? CPP_NAME : token->type), + /* ??? The C parser does not save the cpp flags of a + token, we need to pass 0 here and we will not get + the source spelling of some tokens but rather the + canonical spelling. */ + token->value, /*flags=*/0); +} + +/* If the next token is of the indicated TYPE, consume it. Otherwise, + issue the error MSGID. If MSGID is NULL then a message has already + been produced and no message will be produced this time. Returns + true if found, false otherwise. */ + +static bool +c_parser_require (c_parser *parser, + enum cpp_ttype type, + const char *msgid) +{ + if (c_parser_next_token_is (parser, type)) + { + c_parser_consume_token (parser); + return true; + } + else + { + c_parser_error (parser, msgid); + return false; + } +} + +/* If the next token is the indicated keyword, consume it. Otherwise, + issue the error MSGID. Returns true if found, false otherwise. */ + +static bool +c_parser_require_keyword (c_parser *parser, + enum rid keyword, + const char *msgid) +{ + if (c_parser_next_token_is_keyword (parser, keyword)) + { + c_parser_consume_token (parser); + return true; + } + else + { + c_parser_error (parser, msgid); + return false; + } +} + +/* Like c_parser_require, except that tokens will be skipped until the + desired token is found. An error message is still produced if the + next token is not as expected. If MSGID is NULL then a message has + already been produced and no message will be produced this + time. */ + +static void +c_parser_skip_until_found (c_parser *parser, + enum cpp_ttype type, + const char *msgid) +{ + unsigned nesting_depth = 0; + + if (c_parser_require (parser, type, msgid)) + return; + + /* Skip tokens until the desired token is found. */ + while (true) + { + /* Peek at the next token. */ + c_token *token = c_parser_peek_token (parser); + /* If we've reached the token we want, consume it and stop. */ + if (token->type == type && !nesting_depth) + { + c_parser_consume_token (parser); + break; + } + + /* If we've run out of tokens, stop. */ + if (token->type == CPP_EOF) + return; + if (token->type == CPP_PRAGMA_EOL && parser->in_pragma) + return; + if (token->type == CPP_OPEN_BRACE + || token->type == CPP_OPEN_PAREN + || token->type == CPP_OPEN_SQUARE) + ++nesting_depth; + else if (token->type == CPP_CLOSE_BRACE + || token->type == CPP_CLOSE_PAREN + || token->type == CPP_CLOSE_SQUARE) + { + if (nesting_depth-- == 0) + break; + } + /* Consume this token. */ + c_parser_consume_token (parser); + } + parser->error = false; +} + +/* Skip tokens until the end of a parameter is found, but do not + consume the comma, semicolon or closing delimiter. */ + +static void +c_parser_skip_to_end_of_parameter (c_parser *parser) +{ + unsigned nesting_depth = 0; + + while (true) + { + c_token *token = c_parser_peek_token (parser); + if ((token->type == CPP_COMMA || token->type == CPP_SEMICOLON) + && !nesting_depth) + break; + /* If we've run out of tokens, stop. */ + if (token->type == CPP_EOF) + return; + if (token->type == CPP_PRAGMA_EOL && parser->in_pragma) + return; + if (token->type == CPP_OPEN_BRACE + || token->type == CPP_OPEN_PAREN + || token->type == CPP_OPEN_SQUARE) + ++nesting_depth; + else if (token->type == CPP_CLOSE_BRACE + || token->type == CPP_CLOSE_PAREN + || token->type == CPP_CLOSE_SQUARE) + { + if (nesting_depth-- == 0) + break; + } + /* Consume this token. */ + c_parser_consume_token (parser); + } + parser->error = false; +} + +/* Expect to be at the end of the pragma directive and consume an + end of line marker. */ + +static void +c_parser_skip_to_pragma_eol (c_parser *parser) +{ + gcc_assert (parser->in_pragma); + parser->in_pragma = false; + + if (!c_parser_require (parser, CPP_PRAGMA_EOL, "expected end of line")) + while (true) + { + c_token *token = c_parser_peek_token (parser); + if (token->type == CPP_EOF) + break; + if (token->type == CPP_PRAGMA_EOL) + { + c_parser_consume_token (parser); + break; + } + c_parser_consume_token (parser); + } + + parser->error = false; +} + +/* Skip tokens until we have consumed an entire block, or until we + have consumed a non-nested ';'. */ + +static void +c_parser_skip_to_end_of_block_or_statement (c_parser *parser) +{ + unsigned nesting_depth = 0; + bool save_error = parser->error; + + while (true) + { + c_token *token; + + /* Peek at the next token. */ + token = c_parser_peek_token (parser); + + switch (token->type) + { + case CPP_EOF: + return; + + case CPP_PRAGMA_EOL: + if (parser->in_pragma) + return; + break; + + case CPP_SEMICOLON: + /* If the next token is a ';', we have reached the + end of the statement. */ + if (!nesting_depth) + { + /* Consume the ';'. */ + c_parser_consume_token (parser); + goto finished; + } + break; + + case CPP_CLOSE_BRACE: + /* If the next token is a non-nested '}', then we have + reached the end of the current block. */ + if (nesting_depth == 0 || --nesting_depth == 0) + { + c_parser_consume_token (parser); + goto finished; + } + break; + + case CPP_OPEN_BRACE: + /* If it the next token is a '{', then we are entering a new + block. Consume the entire block. */ + ++nesting_depth; + break; + + case CPP_PRAGMA: + /* If we see a pragma, consume the whole thing at once. We + have some safeguards against consuming pragmas willy-nilly. + Normally, we'd expect to be here with parser->error set, + which disables these safeguards. But it's possible to get + here for secondary error recovery, after parser->error has + been cleared. */ + c_parser_consume_pragma (parser); + c_parser_skip_to_pragma_eol (parser); + parser->error = save_error; + continue; + + default: + break; + } + + c_parser_consume_token (parser); + } + + finished: + parser->error = false; +} + +/* CPP's options (initialized by c-opts.c). */ +extern cpp_options *cpp_opts; + +/* Save the warning flags which are controlled by __extension__. */ + +static inline int +disable_extension_diagnostics (void) +{ + int ret = (pedantic + | (warn_pointer_arith << 1) + | (warn_traditional << 2) + | (flag_iso << 3) + | (warn_long_long << 4) + | (warn_cxx_compat << 5) + | (warn_overlength_strings << 6)); + cpp_opts->cpp_pedantic = pedantic = 0; + warn_pointer_arith = 0; + cpp_opts->cpp_warn_traditional = warn_traditional = 0; + flag_iso = 0; + cpp_opts->cpp_warn_long_long = warn_long_long = 0; + warn_cxx_compat = 0; + warn_overlength_strings = 0; + return ret; +} + +/* Restore the warning flags which are controlled by __extension__. + FLAGS is the return value from disable_extension_diagnostics. */ + +static inline void +restore_extension_diagnostics (int flags) +{ + cpp_opts->cpp_pedantic = pedantic = flags & 1; + warn_pointer_arith = (flags >> 1) & 1; + cpp_opts->cpp_warn_traditional = warn_traditional = (flags >> 2) & 1; + flag_iso = (flags >> 3) & 1; + cpp_opts->cpp_warn_long_long = warn_long_long = (flags >> 4) & 1; + warn_cxx_compat = (flags >> 5) & 1; + warn_overlength_strings = (flags >> 6) & 1; +} + +/* Possibly kinds of declarator to parse. */ +typedef enum c_dtr_syn { + /* A normal declarator with an identifier. */ + C_DTR_NORMAL, + /* An abstract declarator (maybe empty). */ + C_DTR_ABSTRACT, + /* A parameter declarator: may be either, but after a type name does + not redeclare a typedef name as an identifier if it can + alternatively be interpreted as a typedef name; see DR#009, + applied in C90 TC1, omitted from C99 and reapplied in C99 TC2 + following DR#249. For example, given a typedef T, "int T" and + "int *T" are valid parameter declarations redeclaring T, while + "int (T)" and "int * (T)" and "int (T[])" and "int (T (int))" are + abstract declarators rather than involving redundant parentheses; + the same applies with attributes inside the parentheses before + "T". */ + C_DTR_PARM +} c_dtr_syn; + +/* The binary operation precedence levels, where 0 is a dummy lowest level + used for the bottom of the stack. */ +enum c_parser_prec { + PREC_NONE, + PREC_LOGOR, + PREC_LOGAND, + PREC_BITOR, + PREC_BITXOR, + PREC_BITAND, + PREC_EQ, + PREC_REL, + PREC_SHIFT, + PREC_ADD, + PREC_MULT, + NUM_PRECS +}; + +static void c_parser_external_declaration (c_parser *); +static void c_parser_asm_definition (c_parser *); +static void c_parser_declaration_or_fndef (c_parser *, bool, bool, bool, + bool, bool, tree *); +static void c_parser_static_assert_declaration_no_semi (c_parser *); +static void c_parser_static_assert_declaration (c_parser *); +static void c_parser_declspecs (c_parser *, struct c_declspecs *, bool, bool, + bool, enum c_lookahead_kind); +static struct c_typespec c_parser_enum_specifier (c_parser *); +static struct c_typespec c_parser_struct_or_union_specifier (c_parser *); +static tree c_parser_struct_declaration (c_parser *); +static struct c_typespec c_parser_typeof_specifier (c_parser *); +static tree c_parser_alignas_specifier (c_parser *); +static struct c_declarator *c_parser_declarator (c_parser *, bool, c_dtr_syn, + bool *); +static struct c_declarator *c_parser_direct_declarator (c_parser *, bool, + c_dtr_syn, bool *); +static struct c_declarator *c_parser_direct_declarator_inner (c_parser *, + bool, + struct c_declarator *); +static struct c_arg_info *c_parser_parms_declarator (c_parser *, bool, tree); +static struct c_arg_info *c_parser_parms_list_declarator (c_parser *, tree, + tree); +static struct c_parm *c_parser_parameter_declaration (c_parser *, tree); +static tree c_parser_simple_asm_expr (c_parser *); +static tree c_parser_attributes (c_parser *); +static struct c_type_name *c_parser_type_name (c_parser *); +static struct c_expr c_parser_initializer (c_parser *); +static struct c_expr c_parser_braced_init (c_parser *, tree, bool); +static void c_parser_initelt (c_parser *, struct obstack *); +static void c_parser_initval (c_parser *, struct c_expr *, + struct obstack *); +static tree c_parser_compound_statement (c_parser *); +static void c_parser_compound_statement_nostart (c_parser *); +static void c_parser_label (c_parser *); +static void c_parser_statement (c_parser *); +static void c_parser_statement_after_labels (c_parser *); +static void c_parser_if_statement (c_parser *); +static void c_parser_switch_statement (c_parser *); +static void c_parser_while_statement (c_parser *); +static void c_parser_do_statement (c_parser *); +static void c_parser_for_statement (c_parser *); +static tree c_parser_asm_statement (c_parser *); +static tree c_parser_asm_operands (c_parser *, bool); +static tree c_parser_asm_goto_operands (c_parser *); +static tree c_parser_asm_clobbers (c_parser *); +static struct c_expr c_parser_expr_no_commas (c_parser *, struct c_expr *); +static struct c_expr c_parser_conditional_expression (c_parser *, + struct c_expr *); +static struct c_expr c_parser_binary_expression (c_parser *, struct c_expr *, + enum c_parser_prec); +static struct c_expr c_parser_cast_expression (c_parser *, struct c_expr *); +static struct c_expr c_parser_unary_expression (c_parser *); +static struct c_expr c_parser_sizeof_expression (c_parser *); +static struct c_expr c_parser_alignof_expression (c_parser *); +static struct c_expr c_parser_postfix_expression (c_parser *); +static struct c_expr c_parser_postfix_expression_after_paren_type (c_parser *, + struct c_type_name *, + location_t); +static struct c_expr c_parser_postfix_expression_after_primary (c_parser *, + location_t loc, + struct c_expr); +static tree c_parser_transaction (c_parser *, enum rid); +static struct c_expr c_parser_transaction_expression (c_parser *, enum rid); +static tree c_parser_transaction_cancel (c_parser *); +static struct c_expr c_parser_expression (c_parser *); +static struct c_expr c_parser_expression_conv (c_parser *); +static VEC(tree,gc) *c_parser_expr_list (c_parser *, bool, bool, + VEC(tree,gc) **); +static void c_parser_omp_construct (c_parser *); +static void c_parser_omp_threadprivate (c_parser *); +static void c_parser_omp_barrier (c_parser *); +static void c_parser_omp_flush (c_parser *); +static void c_parser_omp_taskwait (c_parser *); +static void c_parser_omp_taskyield (c_parser *); + +enum pragma_context { pragma_external, pragma_stmt, pragma_compound }; +static bool c_parser_pragma (c_parser *, enum pragma_context); + +/* These Objective-C parser functions are only ever called when + compiling Objective-C. */ +static void c_parser_objc_class_definition (c_parser *, tree); +static void c_parser_objc_class_instance_variables (c_parser *); +static void c_parser_objc_class_declaration (c_parser *); +static void c_parser_objc_alias_declaration (c_parser *); +static void c_parser_objc_protocol_definition (c_parser *, tree); +static bool c_parser_objc_method_type (c_parser *); +static void c_parser_objc_method_definition (c_parser *); +static void c_parser_objc_methodprotolist (c_parser *); +static void c_parser_objc_methodproto (c_parser *); +static tree c_parser_objc_method_decl (c_parser *, bool, tree *, tree *); +static tree c_parser_objc_type_name (c_parser *); +static tree c_parser_objc_protocol_refs (c_parser *); +static void c_parser_objc_try_catch_finally_statement (c_parser *); +static void c_parser_objc_synchronized_statement (c_parser *); +static tree c_parser_objc_selector (c_parser *); +static tree c_parser_objc_selector_arg (c_parser *); +static tree c_parser_objc_receiver (c_parser *); +static tree c_parser_objc_message_args (c_parser *); +static tree c_parser_objc_keywordexpr (c_parser *); +static void c_parser_objc_at_property_declaration (c_parser *); +static void c_parser_objc_at_synthesize_declaration (c_parser *); +static void c_parser_objc_at_dynamic_declaration (c_parser *); +static bool c_parser_objc_diagnose_bad_element_prefix + (c_parser *, struct c_declspecs *); + +/* Parse a translation unit (C90 6.7, C99 6.9). + + translation-unit: + external-declarations + + external-declarations: + external-declaration + external-declarations external-declaration + + GNU extensions: + + translation-unit: + empty +*/ + +static void +c_parser_translation_unit (c_parser *parser) +{ + if (c_parser_next_token_is (parser, CPP_EOF)) + { + pedwarn (c_parser_peek_token (parser)->location, OPT_Wpedantic, + "ISO C forbids an empty translation unit"); + } + else + { + void *obstack_position = obstack_alloc (&parser_obstack, 0); + mark_valid_location_for_stdc_pragma (false); + do + { + ggc_collect (); + c_parser_external_declaration (parser); + obstack_free (&parser_obstack, obstack_position); + } + while (c_parser_next_token_is_not (parser, CPP_EOF)); + } +} + +/* Parse an external declaration (C90 6.7, C99 6.9). + + external-declaration: + function-definition + declaration + + GNU extensions: + + external-declaration: + asm-definition + ; + __extension__ external-declaration + + Objective-C: + + external-declaration: + objc-class-definition + objc-class-declaration + objc-alias-declaration + objc-protocol-definition + objc-method-definition + @end +*/ + +static void +c_parser_external_declaration (c_parser *parser) +{ + int ext; + switch (c_parser_peek_token (parser)->type) + { + case CPP_KEYWORD: + switch (c_parser_peek_token (parser)->keyword) + { + case RID_EXTENSION: + ext = disable_extension_diagnostics (); + c_parser_consume_token (parser); + c_parser_external_declaration (parser); + restore_extension_diagnostics (ext); + break; + case RID_ASM: + c_parser_asm_definition (parser); + break; + case RID_AT_INTERFACE: + case RID_AT_IMPLEMENTATION: + gcc_assert (c_dialect_objc ()); + c_parser_objc_class_definition (parser, NULL_TREE); + break; + case RID_AT_CLASS: + gcc_assert (c_dialect_objc ()); + c_parser_objc_class_declaration (parser); + break; + case RID_AT_ALIAS: + gcc_assert (c_dialect_objc ()); + c_parser_objc_alias_declaration (parser); + break; + case RID_AT_PROTOCOL: + gcc_assert (c_dialect_objc ()); + c_parser_objc_protocol_definition (parser, NULL_TREE); + break; + case RID_AT_PROPERTY: + gcc_assert (c_dialect_objc ()); + c_parser_objc_at_property_declaration (parser); + break; + case RID_AT_SYNTHESIZE: + gcc_assert (c_dialect_objc ()); + c_parser_objc_at_synthesize_declaration (parser); + break; + case RID_AT_DYNAMIC: + gcc_assert (c_dialect_objc ()); + c_parser_objc_at_dynamic_declaration (parser); + break; + case RID_AT_END: + gcc_assert (c_dialect_objc ()); + c_parser_consume_token (parser); + objc_finish_implementation (); + break; + default: + goto decl_or_fndef; + } + break; + case CPP_SEMICOLON: + pedwarn (c_parser_peek_token (parser)->location, OPT_Wpedantic, + "ISO C does not allow extra %<;%> outside of a function"); + c_parser_consume_token (parser); + break; + case CPP_PRAGMA: + mark_valid_location_for_stdc_pragma (true); + c_parser_pragma (parser, pragma_external); + mark_valid_location_for_stdc_pragma (false); + break; + case CPP_PLUS: + case CPP_MINUS: + if (c_dialect_objc ()) + { + c_parser_objc_method_definition (parser); + break; + } + /* Else fall through, and yield a syntax error trying to parse + as a declaration or function definition. */ + default: + decl_or_fndef: + /* A declaration or a function definition (or, in Objective-C, + an @interface or @protocol with prefix attributes). We can + only tell which after parsing the declaration specifiers, if + any, and the first declarator. */ + c_parser_declaration_or_fndef (parser, true, true, true, false, true, NULL); + break; + } +} + +/* Parse a declaration or function definition (C90 6.5, 6.7.1, C99 + 6.7, 6.9.1). If FNDEF_OK is true, a function definition is + accepted; otherwise (old-style parameter declarations) only other + declarations are accepted. If STATIC_ASSERT_OK is true, a static + assertion is accepted; otherwise (old-style parameter declarations) + it is not. If NESTED is true, we are inside a function or parsing + old-style parameter declarations; any functions encountered are + nested functions and declaration specifiers are required; otherwise + we are at top level and functions are normal functions and + declaration specifiers may be optional. If EMPTY_OK is true, empty + declarations are OK (subject to all other constraints); otherwise + (old-style parameter declarations) they are diagnosed. If + START_ATTR_OK is true, the declaration specifiers may start with + attributes; otherwise they may not. + OBJC_FOREACH_OBJECT_DECLARATION can be used to get back the parsed + declaration when parsing an Objective-C foreach statement. + + declaration: + declaration-specifiers init-declarator-list[opt] ; + static_assert-declaration + + function-definition: + declaration-specifiers[opt] declarator declaration-list[opt] + compound-statement + + declaration-list: + declaration + declaration-list declaration + + init-declarator-list: + init-declarator + init-declarator-list , init-declarator + + init-declarator: + declarator simple-asm-expr[opt] attributes[opt] + declarator simple-asm-expr[opt] attributes[opt] = initializer + + GNU extensions: + + nested-function-definition: + declaration-specifiers declarator declaration-list[opt] + compound-statement + + Objective-C: + attributes objc-class-definition + attributes objc-category-definition + attributes objc-protocol-definition + + The simple-asm-expr and attributes are GNU extensions. + + This function does not handle __extension__; that is handled in its + callers. ??? Following the old parser, __extension__ may start + external declarations, declarations in functions and declarations + at the start of "for" loops, but not old-style parameter + declarations. + + C99 requires declaration specifiers in a function definition; the + absence is diagnosed through the diagnosis of implicit int. In GNU + C we also allow but diagnose declarations without declaration + specifiers, but only at top level (elsewhere they conflict with + other syntax). + + In Objective-C, declarations of the looping variable in a foreach + statement are exceptionally terminated by 'in' (for example, 'for + (NSObject *object in array) { ... }'). + + OpenMP: + + declaration: + threadprivate-directive */ + +static void +c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok, + bool static_assert_ok, bool empty_ok, + bool nested, bool start_attr_ok, + tree *objc_foreach_object_declaration) +{ + struct c_declspecs *specs; + tree prefix_attrs; + tree all_prefix_attrs; + bool diagnosed_no_specs = false; + location_t here = c_parser_peek_token (parser)->location; + + if (static_assert_ok + && c_parser_next_token_is_keyword (parser, RID_STATIC_ASSERT)) + { + c_parser_static_assert_declaration (parser); + return; + } + specs = build_null_declspecs (); + + /* Try to detect an unknown type name when we have "A B" or "A *B". */ + if (c_parser_peek_token (parser)->type == CPP_NAME + && c_parser_peek_token (parser)->id_kind == C_ID_ID + && (c_parser_peek_2nd_token (parser)->type == CPP_NAME + || c_parser_peek_2nd_token (parser)->type == CPP_MULT) + && (!nested || !lookup_name (c_parser_peek_token (parser)->value))) + { + error_at (here, "unknown type name %qE", + c_parser_peek_token (parser)->value); + + /* Parse declspecs normally to get a correct pointer type, but avoid + a further "fails to be a type name" error. Refuse nested functions + since it is not how the user likely wants us to recover. */ + c_parser_peek_token (parser)->type = CPP_KEYWORD; + c_parser_peek_token (parser)->keyword = RID_VOID; + c_parser_peek_token (parser)->value = error_mark_node; + fndef_ok = !nested; + } + + c_parser_declspecs (parser, specs, true, true, start_attr_ok, cla_nonabstract_decl); + if (parser->error) + { + c_parser_skip_to_end_of_block_or_statement (parser); + return; + } + if (nested && !specs->declspecs_seen_p) + { + c_parser_error (parser, "expected declaration specifiers"); + c_parser_skip_to_end_of_block_or_statement (parser); + return; + } + finish_declspecs (specs); + if (c_parser_next_token_is (parser, CPP_SEMICOLON)) + { + if (empty_ok) + shadow_tag (specs); + else + { + shadow_tag_warned (specs, 1); + pedwarn (here, 0, "empty declaration"); + } + c_parser_consume_token (parser); + return; + } + + /* Provide better error recovery. Note that a type name here is usually + better diagnosed as a redeclaration. */ + if (empty_ok + && specs->typespec_kind == ctsk_tagdef + && c_parser_next_token_starts_declspecs (parser) + && !c_parser_next_token_is (parser, CPP_NAME)) + { + c_parser_error (parser, "expected %<;%>, identifier or %<(%>"); + parser->error = false; + shadow_tag_warned (specs, 1); + return; + } + else if (c_dialect_objc ()) + { + /* Prefix attributes are an error on method decls. */ + switch (c_parser_peek_token (parser)->type) + { + case CPP_PLUS: + case CPP_MINUS: + if (c_parser_objc_diagnose_bad_element_prefix (parser, specs)) + return; + if (specs->attrs) + { + warning_at (c_parser_peek_token (parser)->location, + OPT_Wattributes, + "prefix attributes are ignored for methods"); + specs->attrs = NULL_TREE; + } + if (fndef_ok) + c_parser_objc_method_definition (parser); + else + c_parser_objc_methodproto (parser); + return; + break; + default: + break; + } + /* This is where we parse 'attributes @interface ...', + 'attributes @implementation ...', 'attributes @protocol ...' + (where attributes could be, for example, __attribute__ + ((deprecated)). + */ + switch (c_parser_peek_token (parser)->keyword) + { + case RID_AT_INTERFACE: + { + if (c_parser_objc_diagnose_bad_element_prefix (parser, specs)) + return; + c_parser_objc_class_definition (parser, specs->attrs); + return; + } + break; + case RID_AT_IMPLEMENTATION: + { + if (c_parser_objc_diagnose_bad_element_prefix (parser, specs)) + return; + if (specs->attrs) + { + warning_at (c_parser_peek_token (parser)->location, + OPT_Wattributes, + "prefix attributes are ignored for implementations"); + specs->attrs = NULL_TREE; + } + c_parser_objc_class_definition (parser, NULL_TREE); + return; + } + break; + case RID_AT_PROTOCOL: + { + if (c_parser_objc_diagnose_bad_element_prefix (parser, specs)) + return; + c_parser_objc_protocol_definition (parser, specs->attrs); + return; + } + break; + case RID_AT_ALIAS: + case RID_AT_CLASS: + case RID_AT_END: + case RID_AT_PROPERTY: + if (specs->attrs) + { + c_parser_error (parser, "unexpected attribute"); + specs->attrs = NULL; + } + break; + default: + break; + } + } + + pending_xref_error (); + prefix_attrs = specs->attrs; + all_prefix_attrs = prefix_attrs; + specs->attrs = NULL_TREE; + while (true) + { + struct c_declarator *declarator; + bool dummy = false; + timevar_id_t tv; + tree fnbody; + /* Declaring either one or more declarators (in which case we + should diagnose if there were no declaration specifiers) or a + function definition (in which case the diagnostic for + implicit int suffices). */ + declarator = c_parser_declarator (parser, + specs->typespec_kind != ctsk_none, + C_DTR_NORMAL, &dummy); + if (declarator == NULL) + { + c_parser_skip_to_end_of_block_or_statement (parser); + return; + } + if (c_parser_next_token_is (parser, CPP_EQ) + || c_parser_next_token_is (parser, CPP_COMMA) + || c_parser_next_token_is (parser, CPP_SEMICOLON) + || c_parser_next_token_is_keyword (parser, RID_ASM) + || c_parser_next_token_is_keyword (parser, RID_ATTRIBUTE) + || c_parser_next_token_is_keyword (parser, RID_IN)) + { + tree asm_name = NULL_TREE; + tree postfix_attrs = NULL_TREE; + if (!diagnosed_no_specs && !specs->declspecs_seen_p) + { + diagnosed_no_specs = true; + pedwarn (here, 0, "data definition has no type or storage class"); + } + /* Having seen a data definition, there cannot now be a + function definition. */ + fndef_ok = false; + if (c_parser_next_token_is_keyword (parser, RID_ASM)) + asm_name = c_parser_simple_asm_expr (parser); + if (c_parser_next_token_is_keyword (parser, RID_ATTRIBUTE)) + postfix_attrs = c_parser_attributes (parser); + if (c_parser_next_token_is (parser, CPP_EQ)) + { + tree d; + struct c_expr init; + location_t init_loc; + c_parser_consume_token (parser); + /* The declaration of the variable is in effect while + its initializer is parsed. */ + d = start_decl (declarator, specs, true, + chainon (postfix_attrs, all_prefix_attrs)); + if (!d) + d = error_mark_node; + start_init (d, asm_name, global_bindings_p ()); + init_loc = c_parser_peek_token (parser)->location; + init = c_parser_initializer (parser); + finish_init (); + if (d != error_mark_node) + { + maybe_warn_string_init (TREE_TYPE (d), init); + finish_decl (d, init_loc, init.value, + init.original_type, asm_name); + } + } + else + { + tree d = start_decl (declarator, specs, false, + chainon (postfix_attrs, + all_prefix_attrs)); + if (d) + finish_decl (d, UNKNOWN_LOCATION, NULL_TREE, + NULL_TREE, asm_name); + + if (c_parser_next_token_is_keyword (parser, RID_IN)) + { + if (d) + *objc_foreach_object_declaration = d; + else + *objc_foreach_object_declaration = error_mark_node; + } + } + if (c_parser_next_token_is (parser, CPP_COMMA)) + { + c_parser_consume_token (parser); + if (c_parser_next_token_is_keyword (parser, RID_ATTRIBUTE)) + all_prefix_attrs = chainon (c_parser_attributes (parser), + prefix_attrs); + else + all_prefix_attrs = prefix_attrs; + continue; + } + else if (c_parser_next_token_is (parser, CPP_SEMICOLON)) + { + c_parser_consume_token (parser); + return; + } + else if (c_parser_next_token_is_keyword (parser, RID_IN)) + { + /* This can only happen in Objective-C: we found the + 'in' that terminates the declaration inside an + Objective-C foreach statement. Do not consume the + token, so that the caller can use it to determine + that this indeed is a foreach context. */ + return; + } + else + { + c_parser_error (parser, "expected %<,%> or %<;%>"); + c_parser_skip_to_end_of_block_or_statement (parser); + return; + } + } + else if (!fndef_ok) + { + c_parser_error (parser, "expected %<=%>, %<,%>, %<;%>, " + "%<asm%> or %<__attribute__%>"); + c_parser_skip_to_end_of_block_or_statement (parser); + return; + } + /* Function definition (nested or otherwise). */ + if (nested) + { + pedwarn (here, OPT_Wpedantic, "ISO C forbids nested functions"); + c_push_function_context (); + } + if (!start_function (specs, declarator, all_prefix_attrs)) + { + /* This can appear in many cases looking nothing like a + function definition, so we don't give a more specific + error suggesting there was one. */ + c_parser_error (parser, "expected %<=%>, %<,%>, %<;%>, %<asm%> " + "or %<__attribute__%>"); + if (nested) + c_pop_function_context (); + break; + } + + if (DECL_DECLARED_INLINE_P (current_function_decl)) + tv = TV_PARSE_INLINE; + else + tv = TV_PARSE_FUNC; + timevar_push (tv); + + /* Parse old-style parameter declarations. ??? Attributes are + not allowed to start declaration specifiers here because of a + syntax conflict between a function declaration with attribute + suffix and a function definition with an attribute prefix on + first old-style parameter declaration. Following the old + parser, they are not accepted on subsequent old-style + parameter declarations either. However, there is no + ambiguity after the first declaration, nor indeed on the + first as long as we don't allow postfix attributes after a + declarator with a nonempty identifier list in a definition; + and postfix attributes have never been accepted here in + function definitions either. */ + while (c_parser_next_token_is_not (parser, CPP_EOF) + && c_parser_next_token_is_not (parser, CPP_OPEN_BRACE)) + c_parser_declaration_or_fndef (parser, false, false, false, + true, false, NULL); + store_parm_decls (); + DECL_STRUCT_FUNCTION (current_function_decl)->function_start_locus + = c_parser_peek_token (parser)->location; + fnbody = c_parser_compound_statement (parser); + if (nested) + { + tree decl = current_function_decl; + /* Mark nested functions as needing static-chain initially. + lower_nested_functions will recompute it but the + DECL_STATIC_CHAIN flag is also used before that happens, + by initializer_constant_valid_p. See gcc.dg/nested-fn-2.c. */ + DECL_STATIC_CHAIN (decl) = 1; + add_stmt (fnbody); + finish_function (); + c_pop_function_context (); + add_stmt (build_stmt (DECL_SOURCE_LOCATION (decl), DECL_EXPR, decl)); + } + else + { + add_stmt (fnbody); + finish_function (); + } + + timevar_pop (tv); + break; + } +} + +/* Parse an asm-definition (asm() outside a function body). This is a + GNU extension. + + asm-definition: + simple-asm-expr ; +*/ + +static void +c_parser_asm_definition (c_parser *parser) +{ + tree asm_str = c_parser_simple_asm_expr (parser); + if (asm_str) + add_asm_node (asm_str); + c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>"); +} + +/* Parse a static assertion (C11 6.7.10). + + static_assert-declaration: + static_assert-declaration-no-semi ; +*/ + +static void +c_parser_static_assert_declaration (c_parser *parser) +{ + c_parser_static_assert_declaration_no_semi (parser); + if (parser->error + || !c_parser_require (parser, CPP_SEMICOLON, "expected %<;%>")) + c_parser_skip_to_end_of_block_or_statement (parser); +} + +/* Parse a static assertion (C11 6.7.10), without the trailing + semicolon. + + static_assert-declaration-no-semi: + _Static_assert ( constant-expression , string-literal ) +*/ + +static void +c_parser_static_assert_declaration_no_semi (c_parser *parser) +{ + location_t assert_loc, value_loc; + tree value; + tree string; + + gcc_assert (c_parser_next_token_is_keyword (parser, RID_STATIC_ASSERT)); + assert_loc = c_parser_peek_token (parser)->location; + if (!flag_isoc11) + { + if (flag_isoc99) + pedwarn (assert_loc, OPT_Wpedantic, + "ISO C99 does not support %<_Static_assert%>"); + else + pedwarn (assert_loc, OPT_Wpedantic, + "ISO C90 does not support %<_Static_assert%>"); + } + c_parser_consume_token (parser); + if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) + return; + value_loc = c_parser_peek_token (parser)->location; + value = c_parser_expr_no_commas (parser, NULL).value; + parser->lex_untranslated_string = true; + if (!c_parser_require (parser, CPP_COMMA, "expected %<,%>")) + { + parser->lex_untranslated_string = false; + return; + } + switch (c_parser_peek_token (parser)->type) + { + case CPP_STRING: + case CPP_STRING16: + case CPP_STRING32: + case CPP_WSTRING: + case CPP_UTF8STRING: + string = c_parser_peek_token (parser)->value; + c_parser_consume_token (parser); + parser->lex_untranslated_string = false; + break; + default: + c_parser_error (parser, "expected string literal"); + parser->lex_untranslated_string = false; + return; + } + c_parser_require (parser, CPP_CLOSE_PAREN, "expected %<)%>"); + + if (!INTEGRAL_TYPE_P (TREE_TYPE (value))) + { + error_at (value_loc, "expression in static assertion is not an integer"); + return; + } + if (TREE_CODE (value) != INTEGER_CST) + { + value = c_fully_fold (value, false, NULL); + if (TREE_CODE (value) == INTEGER_CST) + pedwarn (value_loc, OPT_Wpedantic, "expression in static assertion " + "is not an integer constant expression"); + } + if (TREE_CODE (value) != INTEGER_CST) + { + error_at (value_loc, "expression in static assertion is not constant"); + return; + } + constant_expression_warning (value); + if (integer_zerop (value)) + error_at (assert_loc, "static assertion failed: %E", string); +} + +/* Parse some declaration specifiers (possibly none) (C90 6.5, C99 + 6.7), adding them to SPECS (which may already include some). + Storage class specifiers are accepted iff SCSPEC_OK; type + specifiers are accepted iff TYPESPEC_OK; attributes are accepted at + the start iff START_ATTR_OK. + + declaration-specifiers: + storage-class-specifier declaration-specifiers[opt] + type-specifier declaration-specifiers[opt] + type-qualifier declaration-specifiers[opt] + function-specifier declaration-specifiers[opt] + alignment-specifier declaration-specifiers[opt] + + Function specifiers (inline) are from C99, and are currently + handled as storage class specifiers, as is __thread. Alignment + specifiers are from C11. + + C90 6.5.1, C99 6.7.1: + storage-class-specifier: + typedef + extern + static + auto + register + + C99 6.7.4: + function-specifier: + inline + _Noreturn + + (_Noreturn is new in C11.) + + C90 6.5.2, C99 6.7.2: + type-specifier: + void + char + short + int + long + float + double + signed + unsigned + _Bool + _Complex + [_Imaginary removed in C99 TC2] + struct-or-union-specifier + enum-specifier + typedef-name + + (_Bool and _Complex are new in C99.) + + C90 6.5.3, C99 6.7.3: + + type-qualifier: + const + restrict + volatile + address-space-qualifier + + (restrict is new in C99.) + + GNU extensions: + + declaration-specifiers: + attributes declaration-specifiers[opt] + + type-qualifier: + address-space + + address-space: + identifier recognized by the target + + storage-class-specifier: + __thread + + type-specifier: + typeof-specifier + __int128 + _Decimal32 + _Decimal64 + _Decimal128 + _Fract + _Accum + _Sat + + (_Fract, _Accum, and _Sat are new from ISO/IEC DTR 18037: + http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1169.pdf) + + Objective-C: + + type-specifier: + class-name objc-protocol-refs[opt] + typedef-name objc-protocol-refs + objc-protocol-refs +*/ + +static void +c_parser_declspecs (c_parser *parser, struct c_declspecs *specs, + bool scspec_ok, bool typespec_ok, bool start_attr_ok, + enum c_lookahead_kind la) +{ + bool attrs_ok = start_attr_ok; + bool seen_type = specs->typespec_kind != ctsk_none; + + if (!typespec_ok) + gcc_assert (la == cla_prefer_id); + + while (c_parser_next_token_is (parser, CPP_NAME) + || c_parser_next_token_is (parser, CPP_KEYWORD) + || (c_dialect_objc () && c_parser_next_token_is (parser, CPP_LESS))) + { + struct c_typespec t; + tree attrs; + tree align; + location_t loc = c_parser_peek_token (parser)->location; + + /* If we cannot accept a type, exit if the next token must start + one. Also, if we already have seen a tagged definition, + a typename would be an error anyway and likely the user + has simply forgotten a semicolon, so we exit. */ + if ((!typespec_ok || specs->typespec_kind == ctsk_tagdef) + && c_parser_next_tokens_start_typename (parser, la) + && !c_parser_next_token_is_qualifier (parser)) + break; + + if (c_parser_next_token_is (parser, CPP_NAME)) + { + c_token *name_token = c_parser_peek_token (parser); + tree value = name_token->value; + c_id_kind kind = name_token->id_kind; + + if (kind == C_ID_ADDRSPACE) + { + addr_space_t as + = name_token->keyword - RID_FIRST_ADDR_SPACE; + declspecs_add_addrspace (name_token->location, specs, as); + c_parser_consume_token (parser); + attrs_ok = true; + continue; + } + + gcc_assert (!c_parser_next_token_is_qualifier (parser)); + + /* If we cannot accept a type, and the next token must start one, + exit. Do the same if we already have seen a tagged definition, + since it would be an error anyway and likely the user has simply + forgotten a semicolon. */ + if (seen_type || !c_parser_next_tokens_start_typename (parser, la)) + break; + + /* Now at an unknown typename (C_ID_ID), a C_ID_TYPENAME or + a C_ID_CLASSNAME. */ + c_parser_consume_token (parser); + seen_type = true; + attrs_ok = true; + if (kind == C_ID_ID) + { + error ("unknown type name %qE", value); + t.kind = ctsk_typedef; + t.spec = error_mark_node; + } + else if (kind == C_ID_TYPENAME + && (!c_dialect_objc () + || c_parser_next_token_is_not (parser, CPP_LESS))) + { + t.kind = ctsk_typedef; + /* For a typedef name, record the meaning, not the name. + In case of 'foo foo, bar;'. */ + t.spec = lookup_name (value); + } + else + { + tree proto = NULL_TREE; + gcc_assert (c_dialect_objc ()); + t.kind = ctsk_objc; + if (c_parser_next_token_is (parser, CPP_LESS)) + proto = c_parser_objc_protocol_refs (parser); + t.spec = objc_get_protocol_qualified_type (value, proto); + } + t.expr = NULL_TREE; + t.expr_const_operands = true; + declspecs_add_type (name_token->location, specs, t); + continue; + } + if (c_parser_next_token_is (parser, CPP_LESS)) + { + /* Make "<SomeProtocol>" equivalent to "id <SomeProtocol>" - + nisse@lysator.liu.se. */ + tree proto; + gcc_assert (c_dialect_objc ()); + if (!typespec_ok || seen_type) + break; + proto = c_parser_objc_protocol_refs (parser); + t.kind = ctsk_objc; + t.spec = objc_get_protocol_qualified_type (NULL_TREE, proto); + t.expr = NULL_TREE; + t.expr_const_operands = true; + declspecs_add_type (loc, specs, t); + continue; + } + gcc_assert (c_parser_next_token_is (parser, CPP_KEYWORD)); + switch (c_parser_peek_token (parser)->keyword) + { + case RID_STATIC: + case RID_EXTERN: + case RID_REGISTER: + case RID_TYPEDEF: + case RID_INLINE: + case RID_NORETURN: + case RID_AUTO: + case RID_THREAD: + if (!scspec_ok) + goto out; + attrs_ok = true; + /* TODO: Distinguish between function specifiers (inline, noreturn) + and storage class specifiers, either here or in + declspecs_add_scspec. */ + declspecs_add_scspec (loc, specs, + c_parser_peek_token (parser)->value); + c_parser_consume_token (parser); + break; + case RID_UNSIGNED: + case RID_LONG: + case RID_INT128: + case RID_SHORT: + case RID_SIGNED: + case RID_COMPLEX: + case RID_INT: + case RID_CHAR: + case RID_FLOAT: + case RID_DOUBLE: + case RID_VOID: + case RID_DFLOAT32: + case RID_DFLOAT64: + case RID_DFLOAT128: + case RID_BOOL: + case RID_FRACT: + case RID_ACCUM: + case RID_SAT: + if (!typespec_ok) + goto out; + attrs_ok = true; + seen_type = true; + if (c_dialect_objc ()) + parser->objc_need_raw_identifier = true; + t.kind = ctsk_resword; + t.spec = c_parser_peek_token (parser)->value; + t.expr = NULL_TREE; + t.expr_const_operands = true; + declspecs_add_type (loc, specs, t); + c_parser_consume_token (parser); + break; + case RID_ENUM: + if (!typespec_ok) + goto out; + attrs_ok = true; + seen_type = true; + t = c_parser_enum_specifier (parser); + declspecs_add_type (loc, specs, t); + break; + case RID_STRUCT: + case RID_UNION: + if (!typespec_ok) + goto out; + attrs_ok = true; + seen_type = true; + t = c_parser_struct_or_union_specifier (parser); + invoke_plugin_callbacks (PLUGIN_FINISH_TYPE, t.spec); + declspecs_add_type (loc, specs, t); + break; + case RID_TYPEOF: + /* ??? The old parser rejected typeof after other type + specifiers, but is a syntax error the best way of + handling this? */ + if (!typespec_ok || seen_type) + goto out; + attrs_ok = true; + seen_type = true; + t = c_parser_typeof_specifier (parser); + declspecs_add_type (loc, specs, t); + break; + case RID_CONST: + case RID_VOLATILE: + case RID_RESTRICT: + attrs_ok = true; + declspecs_add_qual (loc, specs, c_parser_peek_token (parser)->value); + c_parser_consume_token (parser); + break; + case RID_ATTRIBUTE: + if (!attrs_ok) + goto out; + attrs = c_parser_attributes (parser); + declspecs_add_attrs (loc, specs, attrs); + break; + case RID_ALIGNAS: + align = c_parser_alignas_specifier (parser); + declspecs_add_alignas (loc, specs, align); + break; + default: + goto out; + } + } + out: ; +} + +/* Parse an enum specifier (C90 6.5.2.2, C99 6.7.2.2). + + enum-specifier: + enum attributes[opt] identifier[opt] { enumerator-list } attributes[opt] + enum attributes[opt] identifier[opt] { enumerator-list , } attributes[opt] + enum attributes[opt] identifier + + The form with trailing comma is new in C99. The forms with + attributes are GNU extensions. In GNU C, we accept any expression + without commas in the syntax (assignment expressions, not just + conditional expressions); assignment expressions will be diagnosed + as non-constant. + + enumerator-list: + enumerator + enumerator-list , enumerator + + enumerator: + enumeration-constant + enumeration-constant = constant-expression +*/ + +static struct c_typespec +c_parser_enum_specifier (c_parser *parser) +{ + struct c_typespec ret; + tree attrs; + tree ident = NULL_TREE; + location_t enum_loc; + location_t ident_loc = UNKNOWN_LOCATION; /* Quiet warning. */ + gcc_assert (c_parser_next_token_is_keyword (parser, RID_ENUM)); + enum_loc = c_parser_peek_token (parser)->location; + c_parser_consume_token (parser); + attrs = c_parser_attributes (parser); + enum_loc = c_parser_peek_token (parser)->location; + /* Set the location in case we create a decl now. */ + c_parser_set_source_position_from_token (c_parser_peek_token (parser)); + if (c_parser_next_token_is (parser, CPP_NAME)) + { + ident = c_parser_peek_token (parser)->value; + ident_loc = c_parser_peek_token (parser)->location; + enum_loc = ident_loc; + c_parser_consume_token (parser); + } + if (c_parser_next_token_is (parser, CPP_OPEN_BRACE)) + { + /* Parse an enum definition. */ + struct c_enum_contents the_enum; + tree type; + tree postfix_attrs; + /* We chain the enumerators in reverse order, then put them in + forward order at the end. */ + tree values; + timevar_push (TV_PARSE_ENUM); + type = start_enum (enum_loc, &the_enum, ident); + values = NULL_TREE; + c_parser_consume_token (parser); + while (true) + { + tree enum_id; + tree enum_value; + tree enum_decl; + bool seen_comma; + c_token *token; + location_t comma_loc = UNKNOWN_LOCATION; /* Quiet warning. */ + location_t decl_loc, value_loc; + if (c_parser_next_token_is_not (parser, CPP_NAME)) + { + c_parser_error (parser, "expected identifier"); + c_parser_skip_until_found (parser, CPP_CLOSE_BRACE, NULL); + values = error_mark_node; + break; + } + token = c_parser_peek_token (parser); + enum_id = token->value; + /* Set the location in case we create a decl now. */ + c_parser_set_source_position_from_token (token); + decl_loc = value_loc = token->location; + c_parser_consume_token (parser); + if (c_parser_next_token_is (parser, CPP_EQ)) + { + c_parser_consume_token (parser); + value_loc = c_parser_peek_token (parser)->location; + enum_value = c_parser_expr_no_commas (parser, NULL).value; + } + else + enum_value = NULL_TREE; + enum_decl = build_enumerator (decl_loc, value_loc, + &the_enum, enum_id, enum_value); + TREE_CHAIN (enum_decl) = values; + values = enum_decl; + seen_comma = false; + if (c_parser_next_token_is (parser, CPP_COMMA)) + { + comma_loc = c_parser_peek_token (parser)->location; + seen_comma = true; + c_parser_consume_token (parser); + } + if (c_parser_next_token_is (parser, CPP_CLOSE_BRACE)) + { + if (seen_comma && !flag_isoc99) + pedwarn (comma_loc, OPT_Wpedantic, "comma at end of enumerator list"); + c_parser_consume_token (parser); + break; + } + if (!seen_comma) + { + c_parser_error (parser, "expected %<,%> or %<}%>"); + c_parser_skip_until_found (parser, CPP_CLOSE_BRACE, NULL); + values = error_mark_node; + break; + } + } + postfix_attrs = c_parser_attributes (parser); + ret.spec = finish_enum (type, nreverse (values), + chainon (attrs, postfix_attrs)); + ret.kind = ctsk_tagdef; + ret.expr = NULL_TREE; + ret.expr_const_operands = true; + timevar_pop (TV_PARSE_ENUM); + return ret; + } + else if (!ident) + { + c_parser_error (parser, "expected %<{%>"); + ret.spec = error_mark_node; + ret.kind = ctsk_tagref; + ret.expr = NULL_TREE; + ret.expr_const_operands = true; + return ret; + } + ret = parser_xref_tag (ident_loc, ENUMERAL_TYPE, ident); + /* In ISO C, enumerated types can be referred to only if already + defined. */ + if (pedantic && !COMPLETE_TYPE_P (ret.spec)) + { + gcc_assert (ident); + pedwarn (enum_loc, OPT_Wpedantic, + "ISO C forbids forward references to %<enum%> types"); + } + return ret; +} + +/* Parse a struct or union specifier (C90 6.5.2.1, C99 6.7.2.1). + + struct-or-union-specifier: + struct-or-union attributes[opt] identifier[opt] + { struct-contents } attributes[opt] + struct-or-union attributes[opt] identifier + + struct-contents: + struct-declaration-list + + struct-declaration-list: + struct-declaration ; + struct-declaration-list struct-declaration ; + + GNU extensions: + + struct-contents: + empty + struct-declaration + struct-declaration-list struct-declaration + + struct-declaration-list: + struct-declaration-list ; + ; + + (Note that in the syntax here, unlike that in ISO C, the semicolons + are included here rather than in struct-declaration, in order to + describe the syntax with extra semicolons and missing semicolon at + end.) + + Objective-C: + + struct-declaration-list: + @defs ( class-name ) + + (Note this does not include a trailing semicolon, but can be + followed by further declarations, and gets a pedwarn-if-pedantic + when followed by a semicolon.) */ + +static struct c_typespec +c_parser_struct_or_union_specifier (c_parser *parser) +{ + struct c_typespec ret; + tree attrs; + tree ident = NULL_TREE; + location_t struct_loc; + location_t ident_loc = UNKNOWN_LOCATION; + enum tree_code code; + switch (c_parser_peek_token (parser)->keyword) + { + case RID_STRUCT: + code = RECORD_TYPE; + break; + case RID_UNION: + code = UNION_TYPE; + break; + default: + gcc_unreachable (); + } + struct_loc = c_parser_peek_token (parser)->location; + c_parser_consume_token (parser); + attrs = c_parser_attributes (parser); + + /* Set the location in case we create a decl now. */ + c_parser_set_source_position_from_token (c_parser_peek_token (parser)); + + if (c_parser_next_token_is (parser, CPP_NAME)) + { + ident = c_parser_peek_token (parser)->value; + ident_loc = c_parser_peek_token (parser)->location; + struct_loc = ident_loc; + c_parser_consume_token (parser); + } + if (c_parser_next_token_is (parser, CPP_OPEN_BRACE)) + { + /* Parse a struct or union definition. Start the scope of the + tag before parsing components. */ + struct c_struct_parse_info *struct_info; + tree type = start_struct (struct_loc, code, ident, &struct_info); + tree postfix_attrs; + /* We chain the components in reverse order, then put them in + forward order at the end. Each struct-declaration may + declare multiple components (comma-separated), so we must use + chainon to join them, although when parsing each + struct-declaration we can use TREE_CHAIN directly. + + The theory behind all this is that there will be more + semicolon separated fields than comma separated fields, and + so we'll be minimizing the number of node traversals required + by chainon. */ + tree contents; + timevar_push (TV_PARSE_STRUCT); + contents = NULL_TREE; + c_parser_consume_token (parser); + /* Handle the Objective-C @defs construct, + e.g. foo(sizeof(struct{ @defs(ClassName) }));. */ + if (c_parser_next_token_is_keyword (parser, RID_AT_DEFS)) + { + tree name; + gcc_assert (c_dialect_objc ()); + c_parser_consume_token (parser); + if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) + goto end_at_defs; + if (c_parser_next_token_is (parser, CPP_NAME) + && c_parser_peek_token (parser)->id_kind == C_ID_CLASSNAME) + { + name = c_parser_peek_token (parser)->value; + c_parser_consume_token (parser); + } + else + { + c_parser_error (parser, "expected class name"); + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL); + goto end_at_defs; + } + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, + "expected %<)%>"); + contents = nreverse (objc_get_class_ivars (name)); + } + end_at_defs: + /* Parse the struct-declarations and semicolons. Problems with + semicolons are diagnosed here; empty structures are diagnosed + elsewhere. */ + while (true) + { + tree decls; + /* Parse any stray semicolon. */ + if (c_parser_next_token_is (parser, CPP_SEMICOLON)) + { + pedwarn (c_parser_peek_token (parser)->location, OPT_Wpedantic, + "extra semicolon in struct or union specified"); + c_parser_consume_token (parser); + continue; + } + /* Stop if at the end of the struct or union contents. */ + if (c_parser_next_token_is (parser, CPP_CLOSE_BRACE)) + { + c_parser_consume_token (parser); + break; + } + /* Accept #pragmas at struct scope. */ + if (c_parser_next_token_is (parser, CPP_PRAGMA)) + { + c_parser_pragma (parser, pragma_external); + continue; + } + /* Parse some comma-separated declarations, but not the + trailing semicolon if any. */ + decls = c_parser_struct_declaration (parser); + contents = chainon (decls, contents); + /* If no semicolon follows, either we have a parse error or + are at the end of the struct or union and should + pedwarn. */ + if (c_parser_next_token_is (parser, CPP_SEMICOLON)) + c_parser_consume_token (parser); + else + { + if (c_parser_next_token_is (parser, CPP_CLOSE_BRACE)) + pedwarn (c_parser_peek_token (parser)->location, 0, + "no semicolon at end of struct or union"); + else if (parser->error + || !c_parser_next_token_starts_declspecs (parser)) + { + c_parser_error (parser, "expected %<;%>"); + c_parser_skip_until_found (parser, CPP_CLOSE_BRACE, NULL); + break; + } + + /* If we come here, we have already emitted an error + for an expected `;', identifier or `(', and we also + recovered already. Go on with the next field. */ + } + } + postfix_attrs = c_parser_attributes (parser); + ret.spec = finish_struct (struct_loc, type, nreverse (contents), + chainon (attrs, postfix_attrs), struct_info); + ret.kind = ctsk_tagdef; + ret.expr = NULL_TREE; + ret.expr_const_operands = true; + timevar_pop (TV_PARSE_STRUCT); + return ret; + } + else if (!ident) + { + c_parser_error (parser, "expected %<{%>"); + ret.spec = error_mark_node; + ret.kind = ctsk_tagref; + ret.expr = NULL_TREE; + ret.expr_const_operands = true; + return ret; + } + ret = parser_xref_tag (ident_loc, code, ident); + return ret; +} + +/* Parse a struct-declaration (C90 6.5.2.1, C99 6.7.2.1), *without* + the trailing semicolon. + + struct-declaration: + specifier-qualifier-list struct-declarator-list + static_assert-declaration-no-semi + + specifier-qualifier-list: + type-specifier specifier-qualifier-list[opt] + type-qualifier specifier-qualifier-list[opt] + attributes specifier-qualifier-list[opt] + + struct-declarator-list: + struct-declarator + struct-declarator-list , attributes[opt] struct-declarator + + struct-declarator: + declarator attributes[opt] + declarator[opt] : constant-expression attributes[opt] + + GNU extensions: + + struct-declaration: + __extension__ struct-declaration + specifier-qualifier-list + + Unlike the ISO C syntax, semicolons are handled elsewhere. The use + of attributes where shown is a GNU extension. In GNU C, we accept + any expression without commas in the syntax (assignment + expressions, not just conditional expressions); assignment + expressions will be diagnosed as non-constant. */ + +static tree +c_parser_struct_declaration (c_parser *parser) +{ + struct c_declspecs *specs; + tree prefix_attrs; + tree all_prefix_attrs; + tree decls; + location_t decl_loc; + if (c_parser_next_token_is_keyword (parser, RID_EXTENSION)) + { + int ext; + tree decl; + ext = disable_extension_diagnostics (); + c_parser_consume_token (parser); + decl = c_parser_struct_declaration (parser); + restore_extension_diagnostics (ext); + return decl; + } + if (c_parser_next_token_is_keyword (parser, RID_STATIC_ASSERT)) + { + c_parser_static_assert_declaration_no_semi (parser); + return NULL_TREE; + } + specs = build_null_declspecs (); + decl_loc = c_parser_peek_token (parser)->location; + c_parser_declspecs (parser, specs, false, true, true, cla_nonabstract_decl); + if (parser->error) + return NULL_TREE; + if (!specs->declspecs_seen_p) + { + c_parser_error (parser, "expected specifier-qualifier-list"); + return NULL_TREE; + } + finish_declspecs (specs); + if (c_parser_next_token_is (parser, CPP_SEMICOLON) + || c_parser_next_token_is (parser, CPP_CLOSE_BRACE)) + { + tree ret; + if (specs->typespec_kind == ctsk_none) + { + pedwarn (decl_loc, OPT_Wpedantic, + "ISO C forbids member declarations with no members"); + shadow_tag_warned (specs, pedantic); + ret = NULL_TREE; + } + else + { + /* Support for unnamed structs or unions as members of + structs or unions (which is [a] useful and [b] supports + MS P-SDK). */ + tree attrs = NULL; + + ret = grokfield (c_parser_peek_token (parser)->location, + build_id_declarator (NULL_TREE), specs, + NULL_TREE, &attrs); + if (ret) + decl_attributes (&ret, attrs, 0); + } + return ret; + } + + /* Provide better error recovery. Note that a type name here is valid, + and will be treated as a field name. */ + if (specs->typespec_kind == ctsk_tagdef + && TREE_CODE (specs->type) != ENUMERAL_TYPE + && c_parser_next_token_starts_declspecs (parser) + && !c_parser_next_token_is (parser, CPP_NAME)) + { + c_parser_error (parser, "expected %<;%>, identifier or %<(%>"); + parser->error = false; + return NULL_TREE; + } + + pending_xref_error (); + prefix_attrs = specs->attrs; + all_prefix_attrs = prefix_attrs; + specs->attrs = NULL_TREE; + decls = NULL_TREE; + while (true) + { + /* Declaring one or more declarators or un-named bit-fields. */ + struct c_declarator *declarator; + bool dummy = false; + if (c_parser_next_token_is (parser, CPP_COLON)) + declarator = build_id_declarator (NULL_TREE); + else + declarator = c_parser_declarator (parser, + specs->typespec_kind != ctsk_none, + C_DTR_NORMAL, &dummy); + if (declarator == NULL) + { + c_parser_skip_to_end_of_block_or_statement (parser); + break; + } + if (c_parser_next_token_is (parser, CPP_COLON) + || c_parser_next_token_is (parser, CPP_COMMA) + || c_parser_next_token_is (parser, CPP_SEMICOLON) + || c_parser_next_token_is (parser, CPP_CLOSE_BRACE) + || c_parser_next_token_is_keyword (parser, RID_ATTRIBUTE)) + { + tree postfix_attrs = NULL_TREE; + tree width = NULL_TREE; + tree d; + if (c_parser_next_token_is (parser, CPP_COLON)) + { + c_parser_consume_token (parser); + width = c_parser_expr_no_commas (parser, NULL).value; + } + if (c_parser_next_token_is_keyword (parser, RID_ATTRIBUTE)) + postfix_attrs = c_parser_attributes (parser); + d = grokfield (c_parser_peek_token (parser)->location, + declarator, specs, width, &all_prefix_attrs); + decl_attributes (&d, chainon (postfix_attrs, + all_prefix_attrs), 0); + DECL_CHAIN (d) = decls; + decls = d; + if (c_parser_next_token_is_keyword (parser, RID_ATTRIBUTE)) + all_prefix_attrs = chainon (c_parser_attributes (parser), + prefix_attrs); + else + all_prefix_attrs = prefix_attrs; + if (c_parser_next_token_is (parser, CPP_COMMA)) + c_parser_consume_token (parser); + else if (c_parser_next_token_is (parser, CPP_SEMICOLON) + || c_parser_next_token_is (parser, CPP_CLOSE_BRACE)) + { + /* Semicolon consumed in caller. */ + break; + } + else + { + c_parser_error (parser, "expected %<,%>, %<;%> or %<}%>"); + break; + } + } + else + { + c_parser_error (parser, + "expected %<:%>, %<,%>, %<;%>, %<}%> or " + "%<__attribute__%>"); + break; + } + } + return decls; +} + +/* Parse a typeof specifier (a GNU extension). + + typeof-specifier: + typeof ( expression ) + typeof ( type-name ) +*/ + +static struct c_typespec +c_parser_typeof_specifier (c_parser *parser) +{ + struct c_typespec ret; + ret.kind = ctsk_typeof; + ret.spec = error_mark_node; + ret.expr = NULL_TREE; + ret.expr_const_operands = true; + gcc_assert (c_parser_next_token_is_keyword (parser, RID_TYPEOF)); + c_parser_consume_token (parser); + c_inhibit_evaluation_warnings++; + in_typeof++; + if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) + { + c_inhibit_evaluation_warnings--; + in_typeof--; + return ret; + } + if (c_parser_next_tokens_start_typename (parser, cla_prefer_id)) + { + struct c_type_name *type = c_parser_type_name (parser); + c_inhibit_evaluation_warnings--; + in_typeof--; + if (type != NULL) + { + ret.spec = groktypename (type, &ret.expr, &ret.expr_const_operands); + pop_maybe_used (variably_modified_type_p (ret.spec, NULL_TREE)); + } + } + else + { + bool was_vm; + location_t here = c_parser_peek_token (parser)->location; + struct c_expr expr = c_parser_expression (parser); + c_inhibit_evaluation_warnings--; + in_typeof--; + if (TREE_CODE (expr.value) == COMPONENT_REF + && DECL_C_BIT_FIELD (TREE_OPERAND (expr.value, 1))) + error_at (here, "%<typeof%> applied to a bit-field"); + mark_exp_read (expr.value); + ret.spec = TREE_TYPE (expr.value); + was_vm = variably_modified_type_p (ret.spec, NULL_TREE); + /* This is returned with the type so that when the type is + evaluated, this can be evaluated. */ + if (was_vm) + ret.expr = c_fully_fold (expr.value, false, &ret.expr_const_operands); + pop_maybe_used (was_vm); + } + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); + return ret; +} + +/* Parse an alignment-specifier. + + C11 6.7.5: + + alignment-specifier: + _Alignas ( type-name ) + _Alignas ( constant-expression ) +*/ + +static tree +c_parser_alignas_specifier (c_parser * parser) +{ + tree ret = error_mark_node; + location_t loc = c_parser_peek_token (parser)->location; + gcc_assert (c_parser_next_token_is_keyword (parser, RID_ALIGNAS)); + c_parser_consume_token (parser); + if (!flag_isoc11) + { + if (flag_isoc99) + pedwarn (loc, OPT_Wpedantic, + "ISO C99 does not support %<_Alignas%>"); + else + pedwarn (loc, OPT_Wpedantic, + "ISO C90 does not support %<_Alignas%>"); + } + if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) + return ret; + if (c_parser_next_tokens_start_typename (parser, cla_prefer_id)) + { + struct c_type_name *type = c_parser_type_name (parser); + if (type != NULL) + ret = c_alignof (loc, groktypename (type, NULL, NULL)); + } + else + ret = c_parser_expr_no_commas (parser, NULL).value; + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); + return ret; +} + +/* Parse a declarator, possibly an abstract declarator (C90 6.5.4, + 6.5.5, C99 6.7.5, 6.7.6). If TYPE_SEEN_P then a typedef name may + be redeclared; otherwise it may not. KIND indicates which kind of + declarator is wanted. Returns a valid declarator except in the + case of a syntax error in which case NULL is returned. *SEEN_ID is + set to true if an identifier being declared is seen; this is used + to diagnose bad forms of abstract array declarators and to + determine whether an identifier list is syntactically permitted. + + declarator: + pointer[opt] direct-declarator + + direct-declarator: + identifier + ( attributes[opt] declarator ) + direct-declarator array-declarator + direct-declarator ( parameter-type-list ) + direct-declarator ( identifier-list[opt] ) + + pointer: + * type-qualifier-list[opt] + * type-qualifier-list[opt] pointer + + type-qualifier-list: + type-qualifier + attributes + type-qualifier-list type-qualifier + type-qualifier-list attributes + + parameter-type-list: + parameter-list + parameter-list , ... + + parameter-list: + parameter-declaration + parameter-list , parameter-declaration + + parameter-declaration: + declaration-specifiers declarator attributes[opt] + declaration-specifiers abstract-declarator[opt] attributes[opt] + + identifier-list: + identifier + identifier-list , identifier + + abstract-declarator: + pointer + pointer[opt] direct-abstract-declarator + + direct-abstract-declarator: + ( attributes[opt] abstract-declarator ) + direct-abstract-declarator[opt] array-declarator + direct-abstract-declarator[opt] ( parameter-type-list[opt] ) + + GNU extensions: + + direct-declarator: + direct-declarator ( parameter-forward-declarations + parameter-type-list[opt] ) + + direct-abstract-declarator: + direct-abstract-declarator[opt] ( parameter-forward-declarations + parameter-type-list[opt] ) + + parameter-forward-declarations: + parameter-list ; + parameter-forward-declarations parameter-list ; + + The uses of attributes shown above are GNU extensions. + + Some forms of array declarator are not included in C99 in the + syntax for abstract declarators; these are disallowed elsewhere. + This may be a defect (DR#289). + + This function also accepts an omitted abstract declarator as being + an abstract declarator, although not part of the formal syntax. */ + +static struct c_declarator * +c_parser_declarator (c_parser *parser, bool type_seen_p, c_dtr_syn kind, + bool *seen_id) +{ + /* Parse any initial pointer part. */ + if (c_parser_next_token_is (parser, CPP_MULT)) + { + struct c_declspecs *quals_attrs = build_null_declspecs (); + struct c_declarator *inner; + c_parser_consume_token (parser); + c_parser_declspecs (parser, quals_attrs, false, false, true, cla_prefer_id); + inner = c_parser_declarator (parser, type_seen_p, kind, seen_id); + if (inner == NULL) + return NULL; + else + return make_pointer_declarator (quals_attrs, inner); + } + /* Now we have a direct declarator, direct abstract declarator or + nothing (which counts as a direct abstract declarator here). */ + return c_parser_direct_declarator (parser, type_seen_p, kind, seen_id); +} + +/* Parse a direct declarator or direct abstract declarator; arguments + as c_parser_declarator. */ + +static struct c_declarator * +c_parser_direct_declarator (c_parser *parser, bool type_seen_p, c_dtr_syn kind, + bool *seen_id) +{ + /* The direct declarator must start with an identifier (possibly + omitted) or a parenthesized declarator (possibly abstract). In + an ordinary declarator, initial parentheses must start a + parenthesized declarator. In an abstract declarator or parameter + declarator, they could start a parenthesized declarator or a + parameter list. To tell which, the open parenthesis and any + following attributes must be read. If a declaration specifier + follows, then it is a parameter list; if the specifier is a + typedef name, there might be an ambiguity about redeclaring it, + which is resolved in the direction of treating it as a typedef + name. If a close parenthesis follows, it is also an empty + parameter list, as the syntax does not permit empty abstract + declarators. Otherwise, it is a parenthesized declarator (in + which case the analysis may be repeated inside it, recursively). + + ??? There is an ambiguity in a parameter declaration "int + (__attribute__((foo)) x)", where x is not a typedef name: it + could be an abstract declarator for a function, or declare x with + parentheses. The proper resolution of this ambiguity needs + documenting. At present we follow an accident of the old + parser's implementation, whereby the first parameter must have + some declaration specifiers other than just attributes. Thus as + a parameter declaration it is treated as a parenthesized + parameter named x, and as an abstract declarator it is + rejected. + + ??? Also following the old parser, attributes inside an empty + parameter list are ignored, making it a list not yielding a + prototype, rather than giving an error or making it have one + parameter with implicit type int. + + ??? Also following the old parser, typedef names may be + redeclared in declarators, but not Objective-C class names. */ + + if (kind != C_DTR_ABSTRACT + && c_parser_next_token_is (parser, CPP_NAME) + && ((type_seen_p + && (c_parser_peek_token (parser)->id_kind == C_ID_TYPENAME + || c_parser_peek_token (parser)->id_kind == C_ID_CLASSNAME)) + || c_parser_peek_token (parser)->id_kind == C_ID_ID)) + { + struct c_declarator *inner + = build_id_declarator (c_parser_peek_token (parser)->value); + *seen_id = true; + inner->id_loc = c_parser_peek_token (parser)->location; + c_parser_consume_token (parser); + return c_parser_direct_declarator_inner (parser, *seen_id, inner); + } + + if (kind != C_DTR_NORMAL + && c_parser_next_token_is (parser, CPP_OPEN_SQUARE)) + { + struct c_declarator *inner = build_id_declarator (NULL_TREE); + return c_parser_direct_declarator_inner (parser, *seen_id, inner); + } + + /* Either we are at the end of an abstract declarator, or we have + parentheses. */ + + if (c_parser_next_token_is (parser, CPP_OPEN_PAREN)) + { + tree attrs; + struct c_declarator *inner; + c_parser_consume_token (parser); + attrs = c_parser_attributes (parser); + if (kind != C_DTR_NORMAL + && (c_parser_next_token_starts_declspecs (parser) + || c_parser_next_token_is (parser, CPP_CLOSE_PAREN))) + { + struct c_arg_info *args + = c_parser_parms_declarator (parser, kind == C_DTR_NORMAL, + attrs); + if (args == NULL) + return NULL; + else + { + inner + = build_function_declarator (args, + build_id_declarator (NULL_TREE)); + return c_parser_direct_declarator_inner (parser, *seen_id, + inner); + } + } + /* A parenthesized declarator. */ + inner = c_parser_declarator (parser, type_seen_p, kind, seen_id); + if (inner != NULL && attrs != NULL) + inner = build_attrs_declarator (attrs, inner); + if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN)) + { + c_parser_consume_token (parser); + if (inner == NULL) + return NULL; + else + return c_parser_direct_declarator_inner (parser, *seen_id, inner); + } + else + { + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, + "expected %<)%>"); + return NULL; + } + } + else + { + if (kind == C_DTR_NORMAL) + { + c_parser_error (parser, "expected identifier or %<(%>"); + return NULL; + } + else + return build_id_declarator (NULL_TREE); + } +} + +/* Parse part of a direct declarator or direct abstract declarator, + given that some (in INNER) has already been parsed; ID_PRESENT is + true if an identifier is present, false for an abstract + declarator. */ + +static struct c_declarator * +c_parser_direct_declarator_inner (c_parser *parser, bool id_present, + struct c_declarator *inner) +{ + /* Parse a sequence of array declarators and parameter lists. */ + if (c_parser_next_token_is (parser, CPP_OPEN_SQUARE)) + { + location_t brace_loc = c_parser_peek_token (parser)->location; + struct c_declarator *declarator; + struct c_declspecs *quals_attrs = build_null_declspecs (); + bool static_seen; + bool star_seen; + tree dimen; + c_parser_consume_token (parser); + c_parser_declspecs (parser, quals_attrs, false, false, true, cla_prefer_id); + static_seen = c_parser_next_token_is_keyword (parser, RID_STATIC); + if (static_seen) + c_parser_consume_token (parser); + if (static_seen && !quals_attrs->declspecs_seen_p) + c_parser_declspecs (parser, quals_attrs, false, false, true, cla_prefer_id); + if (!quals_attrs->declspecs_seen_p) + quals_attrs = NULL; + /* If "static" is present, there must be an array dimension. + Otherwise, there may be a dimension, "*", or no + dimension. */ + if (static_seen) + { + star_seen = false; + dimen = c_parser_expr_no_commas (parser, NULL).value; + } + else + { + if (c_parser_next_token_is (parser, CPP_CLOSE_SQUARE)) + { + dimen = NULL_TREE; + star_seen = false; + } + else if (c_parser_next_token_is (parser, CPP_MULT)) + { + if (c_parser_peek_2nd_token (parser)->type == CPP_CLOSE_SQUARE) + { + dimen = NULL_TREE; + star_seen = true; + c_parser_consume_token (parser); + } + else + { + star_seen = false; + dimen = c_parser_expr_no_commas (parser, NULL).value; + } + } + else + { + star_seen = false; + dimen = c_parser_expr_no_commas (parser, NULL).value; + } + } + if (c_parser_next_token_is (parser, CPP_CLOSE_SQUARE)) + c_parser_consume_token (parser); + else + { + c_parser_skip_until_found (parser, CPP_CLOSE_SQUARE, + "expected %<]%>"); + return NULL; + } + if (dimen) + mark_exp_read (dimen); + declarator = build_array_declarator (brace_loc, dimen, quals_attrs, + static_seen, star_seen); + if (declarator == NULL) + return NULL; + inner = set_array_declarator_inner (declarator, inner); + return c_parser_direct_declarator_inner (parser, id_present, inner); + } + else if (c_parser_next_token_is (parser, CPP_OPEN_PAREN)) + { + tree attrs; + struct c_arg_info *args; + c_parser_consume_token (parser); + attrs = c_parser_attributes (parser); + args = c_parser_parms_declarator (parser, id_present, attrs); + if (args == NULL) + return NULL; + else + { + inner = build_function_declarator (args, inner); + return c_parser_direct_declarator_inner (parser, id_present, inner); + } + } + return inner; +} + +/* Parse a parameter list or identifier list, including the closing + parenthesis but not the opening one. ATTRS are the attributes at + the start of the list. ID_LIST_OK is true if an identifier list is + acceptable; such a list must not have attributes at the start. */ + +static struct c_arg_info * +c_parser_parms_declarator (c_parser *parser, bool id_list_ok, tree attrs) +{ + push_scope (); + declare_parm_level (); + /* If the list starts with an identifier, it is an identifier list. + Otherwise, it is either a prototype list or an empty list. */ + if (id_list_ok + && !attrs + && c_parser_next_token_is (parser, CPP_NAME) + && c_parser_peek_token (parser)->id_kind == C_ID_ID + + /* Look ahead to detect typos in type names. */ + && c_parser_peek_2nd_token (parser)->type != CPP_NAME + && c_parser_peek_2nd_token (parser)->type != CPP_MULT + && c_parser_peek_2nd_token (parser)->type != CPP_OPEN_PAREN + && c_parser_peek_2nd_token (parser)->type != CPP_OPEN_SQUARE) + { + tree list = NULL_TREE, *nextp = &list; + while (c_parser_next_token_is (parser, CPP_NAME) + && c_parser_peek_token (parser)->id_kind == C_ID_ID) + { + *nextp = build_tree_list (NULL_TREE, + c_parser_peek_token (parser)->value); + nextp = & TREE_CHAIN (*nextp); + c_parser_consume_token (parser); + if (c_parser_next_token_is_not (parser, CPP_COMMA)) + break; + c_parser_consume_token (parser); + if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN)) + { + c_parser_error (parser, "expected identifier"); + break; + } + } + if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN)) + { + struct c_arg_info *ret = build_arg_info (); + ret->types = list; + c_parser_consume_token (parser); + pop_scope (); + return ret; + } + else + { + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, + "expected %<)%>"); + pop_scope (); + return NULL; + } + } + else + { + struct c_arg_info *ret = c_parser_parms_list_declarator (parser, attrs, + NULL); + pop_scope (); + return ret; + } +} + +/* Parse a parameter list (possibly empty), including the closing + parenthesis but not the opening one. ATTRS are the attributes at + the start of the list. EXPR is NULL or an expression that needs to + be evaluated for the side effects of array size expressions in the + parameters. */ + +static struct c_arg_info * +c_parser_parms_list_declarator (c_parser *parser, tree attrs, tree expr) +{ + bool bad_parm = false; + + /* ??? Following the old parser, forward parameter declarations may + use abstract declarators, and if no real parameter declarations + follow the forward declarations then this is not diagnosed. Also + note as above that attributes are ignored as the only contents of + the parentheses, or as the only contents after forward + declarations. */ + if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN)) + { + struct c_arg_info *ret = build_arg_info (); + c_parser_consume_token (parser); + return ret; + } + if (c_parser_next_token_is (parser, CPP_ELLIPSIS)) + { + struct c_arg_info *ret = build_arg_info (); + + if (flag_allow_parameterless_variadic_functions) + { + /* F (...) is allowed. */ + ret->types = NULL_TREE; + } + else + { + /* Suppress -Wold-style-definition for this case. */ + ret->types = error_mark_node; + error_at (c_parser_peek_token (parser)->location, + "ISO C requires a named argument before %<...%>"); + } + c_parser_consume_token (parser); + if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN)) + { + c_parser_consume_token (parser); + return ret; + } + else + { + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, + "expected %<)%>"); + return NULL; + } + } + /* Nonempty list of parameters, either terminated with semicolon + (forward declarations; recurse) or with close parenthesis (normal + function) or with ", ... )" (variadic function). */ + while (true) + { + /* Parse a parameter. */ + struct c_parm *parm = c_parser_parameter_declaration (parser, attrs); + attrs = NULL_TREE; + if (parm == NULL) + bad_parm = true; + else + push_parm_decl (parm, &expr); + if (c_parser_next_token_is (parser, CPP_SEMICOLON)) + { + tree new_attrs; + c_parser_consume_token (parser); + mark_forward_parm_decls (); + new_attrs = c_parser_attributes (parser); + return c_parser_parms_list_declarator (parser, new_attrs, expr); + } + if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN)) + { + c_parser_consume_token (parser); + if (bad_parm) + return NULL; + else + return get_parm_info (false, expr); + } + if (!c_parser_require (parser, CPP_COMMA, + "expected %<;%>, %<,%> or %<)%>")) + { + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL); + return NULL; + } + if (c_parser_next_token_is (parser, CPP_ELLIPSIS)) + { + c_parser_consume_token (parser); + if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN)) + { + c_parser_consume_token (parser); + if (bad_parm) + return NULL; + else + return get_parm_info (true, expr); + } + else + { + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, + "expected %<)%>"); + return NULL; + } + } + } +} + +/* Parse a parameter declaration. ATTRS are the attributes at the + start of the declaration if it is the first parameter. */ + +static struct c_parm * +c_parser_parameter_declaration (c_parser *parser, tree attrs) +{ + struct c_declspecs *specs; + struct c_declarator *declarator; + tree prefix_attrs; + tree postfix_attrs = NULL_TREE; + bool dummy = false; + + /* Accept #pragmas between parameter declarations. */ + while (c_parser_next_token_is (parser, CPP_PRAGMA)) + c_parser_pragma (parser, pragma_external); + + if (!c_parser_next_token_starts_declspecs (parser)) + { + c_token *token = c_parser_peek_token (parser); + if (parser->error) + return NULL; + c_parser_set_source_position_from_token (token); + if (c_parser_next_tokens_start_typename (parser, cla_prefer_type)) + { + error ("unknown type name %qE", token->value); + parser->error = true; + } + /* ??? In some Objective-C cases '...' isn't applicable so there + should be a different message. */ + else + c_parser_error (parser, + "expected declaration specifiers or %<...%>"); + c_parser_skip_to_end_of_parameter (parser); + return NULL; + } + specs = build_null_declspecs (); + if (attrs) + { + declspecs_add_attrs (input_location, specs, attrs); + attrs = NULL_TREE; + } + c_parser_declspecs (parser, specs, true, true, true, cla_nonabstract_decl); + finish_declspecs (specs); + pending_xref_error (); + prefix_attrs = specs->attrs; + specs->attrs = NULL_TREE; + declarator = c_parser_declarator (parser, + specs->typespec_kind != ctsk_none, + C_DTR_PARM, &dummy); + if (declarator == NULL) + { + c_parser_skip_until_found (parser, CPP_COMMA, NULL); + return NULL; + } + if (c_parser_next_token_is_keyword (parser, RID_ATTRIBUTE)) + postfix_attrs = c_parser_attributes (parser); + return build_c_parm (specs, chainon (postfix_attrs, prefix_attrs), + declarator); +} + +/* Parse a string literal in an asm expression. It should not be + translated, and wide string literals are an error although + permitted by the syntax. This is a GNU extension. + + asm-string-literal: + string-literal + + ??? At present, following the old parser, the caller needs to have + set lex_untranslated_string to 1. It would be better to follow the + C++ parser rather than using this kludge. */ + +static tree +c_parser_asm_string_literal (c_parser *parser) +{ + tree str; + int save_flag = warn_overlength_strings; + warn_overlength_strings = 0; + if (c_parser_next_token_is (parser, CPP_STRING)) + { + str = c_parser_peek_token (parser)->value; + c_parser_consume_token (parser); + } + else if (c_parser_next_token_is (parser, CPP_WSTRING)) + { + error_at (c_parser_peek_token (parser)->location, + "wide string literal in %<asm%>"); + str = build_string (1, ""); + c_parser_consume_token (parser); + } + else + { + c_parser_error (parser, "expected string literal"); + str = NULL_TREE; + } + warn_overlength_strings = save_flag; + return str; +} + +/* Parse a simple asm expression. This is used in restricted + contexts, where a full expression with inputs and outputs does not + make sense. This is a GNU extension. + + simple-asm-expr: + asm ( asm-string-literal ) +*/ + +static tree +c_parser_simple_asm_expr (c_parser *parser) +{ + tree str; + gcc_assert (c_parser_next_token_is_keyword (parser, RID_ASM)); + /* ??? Follow the C++ parser rather than using the + lex_untranslated_string kludge. */ + parser->lex_untranslated_string = true; + c_parser_consume_token (parser); + if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) + { + parser->lex_untranslated_string = false; + return NULL_TREE; + } + str = c_parser_asm_string_literal (parser); + parser->lex_untranslated_string = false; + if (!c_parser_require (parser, CPP_CLOSE_PAREN, "expected %<)%>")) + { + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL); + return NULL_TREE; + } + return str; +} + +static tree +c_parser_attribute_any_word (c_parser *parser) +{ + tree attr_name = NULL_TREE; + + if (c_parser_next_token_is (parser, CPP_KEYWORD)) + { + /* ??? See comment above about what keywords are accepted here. */ + bool ok; + switch (c_parser_peek_token (parser)->keyword) + { + case RID_STATIC: + case RID_UNSIGNED: + case RID_LONG: + case RID_INT128: + case RID_CONST: + case RID_EXTERN: + case RID_REGISTER: + case RID_TYPEDEF: + case RID_SHORT: + case RID_INLINE: + case RID_NORETURN: + case RID_VOLATILE: + case RID_SIGNED: + case RID_AUTO: + case RID_RESTRICT: + case RID_COMPLEX: + case RID_THREAD: + case RID_INT: + case RID_CHAR: + case RID_FLOAT: + case RID_DOUBLE: + case RID_VOID: + case RID_DFLOAT32: + case RID_DFLOAT64: + case RID_DFLOAT128: + case RID_BOOL: + case RID_FRACT: + case RID_ACCUM: + case RID_SAT: + case RID_TRANSACTION_ATOMIC: + case RID_TRANSACTION_CANCEL: + ok = true; + break; + default: + ok = false; + break; + } + if (!ok) + return NULL_TREE; + + /* Accept __attribute__((__const)) as __attribute__((const)) etc. */ + attr_name = ridpointers[(int) c_parser_peek_token (parser)->keyword]; + } + else if (c_parser_next_token_is (parser, CPP_NAME)) + attr_name = c_parser_peek_token (parser)->value; + + return attr_name; +} + +/* Parse (possibly empty) attributes. This is a GNU extension. + + attributes: + empty + attributes attribute + + attribute: + __attribute__ ( ( attribute-list ) ) + + attribute-list: + attrib + attribute_list , attrib + + attrib: + empty + any-word + any-word ( identifier ) + any-word ( identifier , nonempty-expr-list ) + any-word ( expr-list ) + + where the "identifier" must not be declared as a type, and + "any-word" may be any identifier (including one declared as a + type), a reserved word storage class specifier, type specifier or + type qualifier. ??? This still leaves out most reserved keywords + (following the old parser), shouldn't we include them, and why not + allow identifiers declared as types to start the arguments? */ + +static tree +c_parser_attributes (c_parser *parser) +{ + tree attrs = NULL_TREE; + while (c_parser_next_token_is_keyword (parser, RID_ATTRIBUTE)) + { + /* ??? Follow the C++ parser rather than using the + lex_untranslated_string kludge. */ + parser->lex_untranslated_string = true; + c_parser_consume_token (parser); + if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) + { + parser->lex_untranslated_string = false; + return attrs; + } + if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) + { + parser->lex_untranslated_string = false; + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL); + return attrs; + } + /* Parse the attribute list. */ + while (c_parser_next_token_is (parser, CPP_COMMA) + || c_parser_next_token_is (parser, CPP_NAME) + || c_parser_next_token_is (parser, CPP_KEYWORD)) + { + tree attr, attr_name, attr_args; + VEC(tree,gc) *expr_list; + if (c_parser_next_token_is (parser, CPP_COMMA)) + { + c_parser_consume_token (parser); + continue; + } + + attr_name = c_parser_attribute_any_word (parser); + if (attr_name == NULL) + break; + c_parser_consume_token (parser); + if (c_parser_next_token_is_not (parser, CPP_OPEN_PAREN)) + { + attr = build_tree_list (attr_name, NULL_TREE); + attrs = chainon (attrs, attr); + continue; + } + c_parser_consume_token (parser); + /* Parse the attribute contents. If they start with an + identifier which is followed by a comma or close + parenthesis, then the arguments start with that + identifier; otherwise they are an expression list. + In objective-c the identifier may be a classname. */ + if (c_parser_next_token_is (parser, CPP_NAME) + && (c_parser_peek_token (parser)->id_kind == C_ID_ID + || (c_dialect_objc () + && c_parser_peek_token (parser)->id_kind == C_ID_CLASSNAME)) + && ((c_parser_peek_2nd_token (parser)->type == CPP_COMMA) + || (c_parser_peek_2nd_token (parser)->type + == CPP_CLOSE_PAREN))) + { + tree arg1 = c_parser_peek_token (parser)->value; + c_parser_consume_token (parser); + if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN)) + attr_args = build_tree_list (NULL_TREE, arg1); + else + { + tree tree_list; + c_parser_consume_token (parser); + expr_list = c_parser_expr_list (parser, false, true, NULL); + tree_list = build_tree_list_vec (expr_list); + attr_args = tree_cons (NULL_TREE, arg1, tree_list); + release_tree_vector (expr_list); + } + } + else + { + if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN)) + attr_args = NULL_TREE; + else + { + expr_list = c_parser_expr_list (parser, false, true, NULL); + attr_args = build_tree_list_vec (expr_list); + release_tree_vector (expr_list); + } + } + attr = build_tree_list (attr_name, attr_args); + if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN)) + c_parser_consume_token (parser); + else + { + parser->lex_untranslated_string = false; + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, + "expected %<)%>"); + return attrs; + } + attrs = chainon (attrs, attr); + } + if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN)) + c_parser_consume_token (parser); + else + { + parser->lex_untranslated_string = false; + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, + "expected %<)%>"); + return attrs; + } + if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN)) + c_parser_consume_token (parser); + else + { + parser->lex_untranslated_string = false; + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, + "expected %<)%>"); + return attrs; + } + parser->lex_untranslated_string = false; + } + return attrs; +} + +/* Parse a type name (C90 6.5.5, C99 6.7.6). + + type-name: + specifier-qualifier-list abstract-declarator[opt] +*/ + +static struct c_type_name * +c_parser_type_name (c_parser *parser) +{ + struct c_declspecs *specs = build_null_declspecs (); + struct c_declarator *declarator; + struct c_type_name *ret; + bool dummy = false; + c_parser_declspecs (parser, specs, false, true, true, cla_prefer_type); + if (!specs->declspecs_seen_p) + { + c_parser_error (parser, "expected specifier-qualifier-list"); + return NULL; + } + if (specs->type != error_mark_node) + { + pending_xref_error (); + finish_declspecs (specs); + } + declarator = c_parser_declarator (parser, + specs->typespec_kind != ctsk_none, + C_DTR_ABSTRACT, &dummy); + if (declarator == NULL) + return NULL; + ret = XOBNEW (&parser_obstack, struct c_type_name); + ret->specs = specs; + ret->declarator = declarator; + return ret; +} + +/* Parse an initializer (C90 6.5.7, C99 6.7.8). + + initializer: + assignment-expression + { initializer-list } + { initializer-list , } + + initializer-list: + designation[opt] initializer + initializer-list , designation[opt] initializer + + designation: + designator-list = + + designator-list: + designator + designator-list designator + + designator: + array-designator + . identifier + + array-designator: + [ constant-expression ] + + GNU extensions: + + initializer: + { } + + designation: + array-designator + identifier : + + array-designator: + [ constant-expression ... constant-expression ] + + Any expression without commas is accepted in the syntax for the + constant-expressions, with non-constant expressions rejected later. + + This function is only used for top-level initializers; for nested + ones, see c_parser_initval. */ + +static struct c_expr +c_parser_initializer (c_parser *parser) +{ + if (c_parser_next_token_is (parser, CPP_OPEN_BRACE)) + return c_parser_braced_init (parser, NULL_TREE, false); + else + { + struct c_expr ret; + location_t loc = c_parser_peek_token (parser)->location; + ret = c_parser_expr_no_commas (parser, NULL); + if (TREE_CODE (ret.value) != STRING_CST + && TREE_CODE (ret.value) != COMPOUND_LITERAL_EXPR) + ret = default_function_array_read_conversion (loc, ret); + return ret; + } +} + +/* Parse a braced initializer list. TYPE is the type specified for a + compound literal, and NULL_TREE for other initializers and for + nested braced lists. NESTED_P is true for nested braced lists, + false for the list of a compound literal or the list that is the + top-level initializer in a declaration. */ + +static struct c_expr +c_parser_braced_init (c_parser *parser, tree type, bool nested_p) +{ + struct c_expr ret; + struct obstack braced_init_obstack; + location_t brace_loc = c_parser_peek_token (parser)->location; + gcc_obstack_init (&braced_init_obstack); + gcc_assert (c_parser_next_token_is (parser, CPP_OPEN_BRACE)); + c_parser_consume_token (parser); + if (nested_p) + push_init_level (0, &braced_init_obstack); + else + really_start_incremental_init (type); + if (c_parser_next_token_is (parser, CPP_CLOSE_BRACE)) + { + pedwarn (brace_loc, OPT_Wpedantic, "ISO C forbids empty initializer braces"); + } + else + { + /* Parse a non-empty initializer list, possibly with a trailing + comma. */ + while (true) + { + c_parser_initelt (parser, &braced_init_obstack); + if (parser->error) + break; + if (c_parser_next_token_is (parser, CPP_COMMA)) + c_parser_consume_token (parser); + else + break; + if (c_parser_next_token_is (parser, CPP_CLOSE_BRACE)) + break; + } + } + if (c_parser_next_token_is_not (parser, CPP_CLOSE_BRACE)) + { + ret.value = error_mark_node; + ret.original_code = ERROR_MARK; + ret.original_type = NULL; + c_parser_skip_until_found (parser, CPP_CLOSE_BRACE, "expected %<}%>"); + pop_init_level (0, &braced_init_obstack); + obstack_free (&braced_init_obstack, NULL); + return ret; + } + c_parser_consume_token (parser); + ret = pop_init_level (0, &braced_init_obstack); + obstack_free (&braced_init_obstack, NULL); + return ret; +} + +/* Parse a nested initializer, including designators. */ + +static void +c_parser_initelt (c_parser *parser, struct obstack * braced_init_obstack) +{ + /* Parse any designator or designator list. A single array + designator may have the subsequent "=" omitted in GNU C, but a + longer list or a structure member designator may not. */ + if (c_parser_next_token_is (parser, CPP_NAME) + && c_parser_peek_2nd_token (parser)->type == CPP_COLON) + { + /* Old-style structure member designator. */ + set_init_label (c_parser_peek_token (parser)->value, + braced_init_obstack); + /* Use the colon as the error location. */ + pedwarn (c_parser_peek_2nd_token (parser)->location, OPT_Wpedantic, + "obsolete use of designated initializer with %<:%>"); + c_parser_consume_token (parser); + c_parser_consume_token (parser); + } + else + { + /* des_seen is 0 if there have been no designators, 1 if there + has been a single array designator and 2 otherwise. */ + int des_seen = 0; + /* Location of a designator. */ + location_t des_loc = UNKNOWN_LOCATION; /* Quiet warning. */ + while (c_parser_next_token_is (parser, CPP_OPEN_SQUARE) + || c_parser_next_token_is (parser, CPP_DOT)) + { + int des_prev = des_seen; + if (!des_seen) + des_loc = c_parser_peek_token (parser)->location; + if (des_seen < 2) + des_seen++; + if (c_parser_next_token_is (parser, CPP_DOT)) + { + des_seen = 2; + c_parser_consume_token (parser); + if (c_parser_next_token_is (parser, CPP_NAME)) + { + set_init_label (c_parser_peek_token (parser)->value, + braced_init_obstack); + c_parser_consume_token (parser); + } + else + { + struct c_expr init; + init.value = error_mark_node; + init.original_code = ERROR_MARK; + init.original_type = NULL; + c_parser_error (parser, "expected identifier"); + c_parser_skip_until_found (parser, CPP_COMMA, NULL); + process_init_element (init, false, braced_init_obstack); + return; + } + } + else + { + tree first, second; + location_t ellipsis_loc = UNKNOWN_LOCATION; /* Quiet warning. */ + /* ??? Following the old parser, [ objc-receiver + objc-message-args ] is accepted as an initializer, + being distinguished from a designator by what follows + the first assignment expression inside the square + brackets, but after a first array designator a + subsequent square bracket is for Objective-C taken to + start an expression, using the obsolete form of + designated initializer without '=', rather than + possibly being a second level of designation: in LALR + terms, the '[' is shifted rather than reducing + designator to designator-list. */ + if (des_prev == 1 && c_dialect_objc ()) + { + des_seen = des_prev; + break; + } + if (des_prev == 0 && c_dialect_objc ()) + { + /* This might be an array designator or an + Objective-C message expression. If the former, + continue parsing here; if the latter, parse the + remainder of the initializer given the starting + primary-expression. ??? It might make sense to + distinguish when des_prev == 1 as well; see + previous comment. */ + tree rec, args; + struct c_expr mexpr; + c_parser_consume_token (parser); + if (c_parser_peek_token (parser)->type == CPP_NAME + && ((c_parser_peek_token (parser)->id_kind + == C_ID_TYPENAME) + || (c_parser_peek_token (parser)->id_kind + == C_ID_CLASSNAME))) + { + /* Type name receiver. */ + tree id = c_parser_peek_token (parser)->value; + c_parser_consume_token (parser); + rec = objc_get_class_reference (id); + goto parse_message_args; + } + first = c_parser_expr_no_commas (parser, NULL).value; + mark_exp_read (first); + if (c_parser_next_token_is (parser, CPP_ELLIPSIS) + || c_parser_next_token_is (parser, CPP_CLOSE_SQUARE)) + goto array_desig_after_first; + /* Expression receiver. So far only one part + without commas has been parsed; there might be + more of the expression. */ + rec = first; + while (c_parser_next_token_is (parser, CPP_COMMA)) + { + struct c_expr next; + location_t comma_loc, exp_loc; + comma_loc = c_parser_peek_token (parser)->location; + c_parser_consume_token (parser); + exp_loc = c_parser_peek_token (parser)->location; + next = c_parser_expr_no_commas (parser, NULL); + next = default_function_array_read_conversion (exp_loc, + next); + rec = build_compound_expr (comma_loc, rec, next.value); + } + parse_message_args: + /* Now parse the objc-message-args. */ + args = c_parser_objc_message_args (parser); + c_parser_skip_until_found (parser, CPP_CLOSE_SQUARE, + "expected %<]%>"); + mexpr.value + = objc_build_message_expr (rec, args); + mexpr.original_code = ERROR_MARK; + mexpr.original_type = NULL; + /* Now parse and process the remainder of the + initializer, starting with this message + expression as a primary-expression. */ + c_parser_initval (parser, &mexpr, braced_init_obstack); + return; + } + c_parser_consume_token (parser); + first = c_parser_expr_no_commas (parser, NULL).value; + mark_exp_read (first); + array_desig_after_first: + if (c_parser_next_token_is (parser, CPP_ELLIPSIS)) + { + ellipsis_loc = c_parser_peek_token (parser)->location; + c_parser_consume_token (parser); + second = c_parser_expr_no_commas (parser, NULL).value; + mark_exp_read (second); + } + else + second = NULL_TREE; + if (c_parser_next_token_is (parser, CPP_CLOSE_SQUARE)) + { + c_parser_consume_token (parser); + set_init_index (first, second, braced_init_obstack); + if (second) + pedwarn (ellipsis_loc, OPT_Wpedantic, + "ISO C forbids specifying range of elements to initialize"); + } + else + c_parser_skip_until_found (parser, CPP_CLOSE_SQUARE, + "expected %<]%>"); + } + } + if (des_seen >= 1) + { + if (c_parser_next_token_is (parser, CPP_EQ)) + { + if (!flag_isoc99) + pedwarn (des_loc, OPT_Wpedantic, + "ISO C90 forbids specifying subobject to initialize"); + c_parser_consume_token (parser); + } + else + { + if (des_seen == 1) + pedwarn (c_parser_peek_token (parser)->location, OPT_Wpedantic, + "obsolete use of designated initializer without %<=%>"); + else + { + struct c_expr init; + init.value = error_mark_node; + init.original_code = ERROR_MARK; + init.original_type = NULL; + c_parser_error (parser, "expected %<=%>"); + c_parser_skip_until_found (parser, CPP_COMMA, NULL); + process_init_element (init, false, braced_init_obstack); + return; + } + } + } + } + c_parser_initval (parser, NULL, braced_init_obstack); +} + +/* Parse a nested initializer; as c_parser_initializer but parses + initializers within braced lists, after any designators have been + applied. If AFTER is not NULL then it is an Objective-C message + expression which is the primary-expression starting the + initializer. */ + +static void +c_parser_initval (c_parser *parser, struct c_expr *after, + struct obstack * braced_init_obstack) +{ + struct c_expr init; + gcc_assert (!after || c_dialect_objc ()); + if (c_parser_next_token_is (parser, CPP_OPEN_BRACE) && !after) + init = c_parser_braced_init (parser, NULL_TREE, true); + else + { + location_t loc = c_parser_peek_token (parser)->location; + init = c_parser_expr_no_commas (parser, after); + if (init.value != NULL_TREE + && TREE_CODE (init.value) != STRING_CST + && TREE_CODE (init.value) != COMPOUND_LITERAL_EXPR) + init = default_function_array_read_conversion (loc, init); + } + process_init_element (init, false, braced_init_obstack); +} + +/* Parse a compound statement (possibly a function body) (C90 6.6.2, + C99 6.8.2). + + compound-statement: + { block-item-list[opt] } + { label-declarations block-item-list } + + block-item-list: + block-item + block-item-list block-item + + block-item: + nested-declaration + statement + + nested-declaration: + declaration + + GNU extensions: + + compound-statement: + { label-declarations block-item-list } + + nested-declaration: + __extension__ nested-declaration + nested-function-definition + + label-declarations: + label-declaration + label-declarations label-declaration + + label-declaration: + __label__ identifier-list ; + + Allowing the mixing of declarations and code is new in C99. The + GNU syntax also permits (not shown above) labels at the end of + compound statements, which yield an error. We don't allow labels + on declarations; this might seem like a natural extension, but + there would be a conflict between attributes on the label and + prefix attributes on the declaration. ??? The syntax follows the + old parser in requiring something after label declarations. + Although they are erroneous if the labels declared aren't defined, + is it useful for the syntax to be this way? + + OpenMP: + + block-item: + openmp-directive + + openmp-directive: + barrier-directive + flush-directive */ + +static tree +c_parser_compound_statement (c_parser *parser) +{ + tree stmt; + location_t brace_loc; + brace_loc = c_parser_peek_token (parser)->location; + if (!c_parser_require (parser, CPP_OPEN_BRACE, "expected %<{%>")) + { + /* Ensure a scope is entered and left anyway to avoid confusion + if we have just prepared to enter a function body. */ + stmt = c_begin_compound_stmt (true); + c_end_compound_stmt (brace_loc, stmt, true); + return error_mark_node; + } + stmt = c_begin_compound_stmt (true); + c_parser_compound_statement_nostart (parser); + return c_end_compound_stmt (brace_loc, stmt, true); +} + +/* Parse a compound statement except for the opening brace. This is + used for parsing both compound statements and statement expressions + (which follow different paths to handling the opening). */ + +static void +c_parser_compound_statement_nostart (c_parser *parser) +{ + bool last_stmt = false; + bool last_label = false; + bool save_valid_for_pragma = valid_location_for_stdc_pragma_p (); + location_t label_loc = UNKNOWN_LOCATION; /* Quiet warning. */ + if (c_parser_next_token_is (parser, CPP_CLOSE_BRACE)) + { + c_parser_consume_token (parser); + return; + } + mark_valid_location_for_stdc_pragma (true); + if (c_parser_next_token_is_keyword (parser, RID_LABEL)) + { + /* Read zero or more forward-declarations for labels that nested + functions can jump to. */ + mark_valid_location_for_stdc_pragma (false); + while (c_parser_next_token_is_keyword (parser, RID_LABEL)) + { + label_loc = c_parser_peek_token (parser)->location; + c_parser_consume_token (parser); + /* Any identifiers, including those declared as type names, + are OK here. */ + while (true) + { + tree label; + if (c_parser_next_token_is_not (parser, CPP_NAME)) + { + c_parser_error (parser, "expected identifier"); + break; + } + label + = declare_label (c_parser_peek_token (parser)->value); + C_DECLARED_LABEL_FLAG (label) = 1; + add_stmt (build_stmt (label_loc, DECL_EXPR, label)); + c_parser_consume_token (parser); + if (c_parser_next_token_is (parser, CPP_COMMA)) + c_parser_consume_token (parser); + else + break; + } + c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>"); + } + pedwarn (label_loc, OPT_Wpedantic, "ISO C forbids label declarations"); + } + /* We must now have at least one statement, label or declaration. */ + if (c_parser_next_token_is (parser, CPP_CLOSE_BRACE)) + { + mark_valid_location_for_stdc_pragma (save_valid_for_pragma); + c_parser_error (parser, "expected declaration or statement"); + c_parser_consume_token (parser); + return; + } + while (c_parser_next_token_is_not (parser, CPP_CLOSE_BRACE)) + { + location_t loc = c_parser_peek_token (parser)->location; + if (c_parser_next_token_is_keyword (parser, RID_CASE) + || c_parser_next_token_is_keyword (parser, RID_DEFAULT) + || (c_parser_next_token_is (parser, CPP_NAME) + && c_parser_peek_2nd_token (parser)->type == CPP_COLON)) + { + if (c_parser_next_token_is_keyword (parser, RID_CASE)) + label_loc = c_parser_peek_2nd_token (parser)->location; + else + label_loc = c_parser_peek_token (parser)->location; + last_label = true; + last_stmt = false; + mark_valid_location_for_stdc_pragma (false); + c_parser_label (parser); + } + else if (!last_label + && c_parser_next_tokens_start_declaration (parser)) + { + last_label = false; + mark_valid_location_for_stdc_pragma (false); + c_parser_declaration_or_fndef (parser, true, true, true, true, true, NULL); + if (last_stmt) + pedwarn_c90 (loc, + (pedantic && !flag_isoc99) + ? OPT_Wpedantic + : OPT_Wdeclaration_after_statement, + "ISO C90 forbids mixed declarations and code"); + last_stmt = false; + } + else if (!last_label + && c_parser_next_token_is_keyword (parser, RID_EXTENSION)) + { + /* __extension__ can start a declaration, but is also an + unary operator that can start an expression. Consume all + but the last of a possible series of __extension__ to + determine which. */ + while (c_parser_peek_2nd_token (parser)->type == CPP_KEYWORD + && (c_parser_peek_2nd_token (parser)->keyword + == RID_EXTENSION)) + c_parser_consume_token (parser); + if (c_token_starts_declaration (c_parser_peek_2nd_token (parser))) + { + int ext; + ext = disable_extension_diagnostics (); + c_parser_consume_token (parser); + last_label = false; + mark_valid_location_for_stdc_pragma (false); + c_parser_declaration_or_fndef (parser, true, true, true, true, + true, NULL); + /* Following the old parser, __extension__ does not + disable this diagnostic. */ + restore_extension_diagnostics (ext); + if (last_stmt) + pedwarn_c90 (loc, (pedantic && !flag_isoc99) + ? OPT_Wpedantic + : OPT_Wdeclaration_after_statement, + "ISO C90 forbids mixed declarations and code"); + last_stmt = false; + } + else + goto statement; + } + else if (c_parser_next_token_is (parser, CPP_PRAGMA)) + { + /* External pragmas, and some omp pragmas, are not associated + with regular c code, and so are not to be considered statements + syntactically. This ensures that the user doesn't put them + places that would turn into syntax errors if the directive + were ignored. */ + if (c_parser_pragma (parser, pragma_compound)) + last_label = false, last_stmt = true; + } + else if (c_parser_next_token_is (parser, CPP_EOF)) + { + mark_valid_location_for_stdc_pragma (save_valid_for_pragma); + c_parser_error (parser, "expected declaration or statement"); + return; + } + else if (c_parser_next_token_is_keyword (parser, RID_ELSE)) + { + if (parser->in_if_block) + { + mark_valid_location_for_stdc_pragma (save_valid_for_pragma); + error_at (loc, """expected %<}%> before %<else%>"); + return; + } + else + { + error_at (loc, "%<else%> without a previous %<if%>"); + c_parser_consume_token (parser); + continue; + } + } + else + { + statement: + last_label = false; + last_stmt = true; + mark_valid_location_for_stdc_pragma (false); + c_parser_statement_after_labels (parser); + } + + parser->error = false; + } + if (last_label) + error_at (label_loc, "label at end of compound statement"); + c_parser_consume_token (parser); + /* Restore the value we started with. */ + mark_valid_location_for_stdc_pragma (save_valid_for_pragma); +} + +/* Parse a label (C90 6.6.1, C99 6.8.1). + + label: + identifier : attributes[opt] + case constant-expression : + default : + + GNU extensions: + + label: + case constant-expression ... constant-expression : + + The use of attributes on labels is a GNU extension. The syntax in + GNU C accepts any expressions without commas, non-constant + expressions being rejected later. */ + +static void +c_parser_label (c_parser *parser) +{ + location_t loc1 = c_parser_peek_token (parser)->location; + tree label = NULL_TREE; + if (c_parser_next_token_is_keyword (parser, RID_CASE)) + { + tree exp1, exp2; + c_parser_consume_token (parser); + exp1 = c_parser_expr_no_commas (parser, NULL).value; + if (c_parser_next_token_is (parser, CPP_COLON)) + { + c_parser_consume_token (parser); + label = do_case (loc1, exp1, NULL_TREE); + } + else if (c_parser_next_token_is (parser, CPP_ELLIPSIS)) + { + c_parser_consume_token (parser); + exp2 = c_parser_expr_no_commas (parser, NULL).value; + if (c_parser_require (parser, CPP_COLON, "expected %<:%>")) + label = do_case (loc1, exp1, exp2); + } + else + c_parser_error (parser, "expected %<:%> or %<...%>"); + } + else if (c_parser_next_token_is_keyword (parser, RID_DEFAULT)) + { + c_parser_consume_token (parser); + if (c_parser_require (parser, CPP_COLON, "expected %<:%>")) + label = do_case (loc1, NULL_TREE, NULL_TREE); + } + else + { + tree name = c_parser_peek_token (parser)->value; + tree tlab; + tree attrs; + location_t loc2 = c_parser_peek_token (parser)->location; + gcc_assert (c_parser_next_token_is (parser, CPP_NAME)); + c_parser_consume_token (parser); + gcc_assert (c_parser_next_token_is (parser, CPP_COLON)); + c_parser_consume_token (parser); + attrs = c_parser_attributes (parser); + tlab = define_label (loc2, name); + if (tlab) + { + decl_attributes (&tlab, attrs, 0); + label = add_stmt (build_stmt (loc1, LABEL_EXPR, tlab)); + } + } + if (label) + { + if (c_parser_next_tokens_start_declaration (parser)) + { + error_at (c_parser_peek_token (parser)->location, + "a label can only be part of a statement and " + "a declaration is not a statement"); + c_parser_declaration_or_fndef (parser, /*fndef_ok*/ false, + /*static_assert_ok*/ true, + /*nested*/ true, /*empty_ok*/ false, + /*start_attr_ok*/ true, NULL); + } + } +} + +/* Parse a statement (C90 6.6, C99 6.8). + + statement: + labeled-statement + compound-statement + expression-statement + selection-statement + iteration-statement + jump-statement + + labeled-statement: + label statement + + expression-statement: + expression[opt] ; + + selection-statement: + if-statement + switch-statement + + iteration-statement: + while-statement + do-statement + for-statement + + jump-statement: + goto identifier ; + continue ; + break ; + return expression[opt] ; + + GNU extensions: + + statement: + asm-statement + + jump-statement: + goto * expression ; + + Objective-C: + + statement: + objc-throw-statement + objc-try-catch-statement + objc-synchronized-statement + + objc-throw-statement: + @throw expression ; + @throw ; + + OpenMP: + + statement: + openmp-construct + + openmp-construct: + parallel-construct + for-construct + sections-construct + single-construct + parallel-for-construct + parallel-sections-construct + master-construct + critical-construct + atomic-construct + ordered-construct + + parallel-construct: + parallel-directive structured-block + + for-construct: + for-directive iteration-statement + + sections-construct: + sections-directive section-scope + + single-construct: + single-directive structured-block + + parallel-for-construct: + parallel-for-directive iteration-statement + + parallel-sections-construct: + parallel-sections-directive section-scope + + master-construct: + master-directive structured-block + + critical-construct: + critical-directive structured-block + + atomic-construct: + atomic-directive expression-statement + + ordered-construct: + ordered-directive structured-block + + Transactional Memory: + + statement: + transaction-statement + transaction-cancel-statement +*/ + +static void +c_parser_statement (c_parser *parser) +{ + while (c_parser_next_token_is_keyword (parser, RID_CASE) + || c_parser_next_token_is_keyword (parser, RID_DEFAULT) + || (c_parser_next_token_is (parser, CPP_NAME) + && c_parser_peek_2nd_token (parser)->type == CPP_COLON)) + c_parser_label (parser); + c_parser_statement_after_labels (parser); +} + +/* Parse a statement, other than a labeled statement. */ + +static void +c_parser_statement_after_labels (c_parser *parser) +{ + location_t loc = c_parser_peek_token (parser)->location; + tree stmt = NULL_TREE; + bool in_if_block = parser->in_if_block; + parser->in_if_block = false; + switch (c_parser_peek_token (parser)->type) + { + case CPP_OPEN_BRACE: + add_stmt (c_parser_compound_statement (parser)); + break; + case CPP_KEYWORD: + switch (c_parser_peek_token (parser)->keyword) + { + case RID_IF: + c_parser_if_statement (parser); + break; + case RID_SWITCH: + c_parser_switch_statement (parser); + break; + case RID_WHILE: + c_parser_while_statement (parser); + break; + case RID_DO: + c_parser_do_statement (parser); + break; + case RID_FOR: + c_parser_for_statement (parser); + break; + case RID_GOTO: + c_parser_consume_token (parser); + if (c_parser_next_token_is (parser, CPP_NAME)) + { + stmt = c_finish_goto_label (loc, + c_parser_peek_token (parser)->value); + c_parser_consume_token (parser); + } + else if (c_parser_next_token_is (parser, CPP_MULT)) + { + tree val; + + c_parser_consume_token (parser); + val = c_parser_expression (parser).value; + mark_exp_read (val); + stmt = c_finish_goto_ptr (loc, val); + } + else + c_parser_error (parser, "expected identifier or %<*%>"); + goto expect_semicolon; + case RID_CONTINUE: + c_parser_consume_token (parser); + stmt = c_finish_bc_stmt (loc, &c_cont_label, false); + goto expect_semicolon; + case RID_BREAK: + c_parser_consume_token (parser); + stmt = c_finish_bc_stmt (loc, &c_break_label, true); + goto expect_semicolon; + case RID_RETURN: + c_parser_consume_token (parser); + if (c_parser_next_token_is (parser, CPP_SEMICOLON)) + { + stmt = c_finish_return (loc, NULL_TREE, NULL_TREE); + c_parser_consume_token (parser); + } + else + { + struct c_expr expr = c_parser_expression_conv (parser); + mark_exp_read (expr.value); + stmt = c_finish_return (loc, expr.value, expr.original_type); + goto expect_semicolon; + } + break; + case RID_ASM: + stmt = c_parser_asm_statement (parser); + break; + case RID_TRANSACTION_ATOMIC: + case RID_TRANSACTION_RELAXED: + stmt = c_parser_transaction (parser, + c_parser_peek_token (parser)->keyword); + break; + case RID_TRANSACTION_CANCEL: + stmt = c_parser_transaction_cancel (parser); + goto expect_semicolon; + case RID_AT_THROW: + gcc_assert (c_dialect_objc ()); + c_parser_consume_token (parser); + if (c_parser_next_token_is (parser, CPP_SEMICOLON)) + { + stmt = objc_build_throw_stmt (loc, NULL_TREE); + c_parser_consume_token (parser); + } + else + { + tree expr = c_parser_expression (parser).value; + expr = c_fully_fold (expr, false, NULL); + stmt = objc_build_throw_stmt (loc, expr); + goto expect_semicolon; + } + break; + case RID_AT_TRY: + gcc_assert (c_dialect_objc ()); + c_parser_objc_try_catch_finally_statement (parser); + break; + case RID_AT_SYNCHRONIZED: + gcc_assert (c_dialect_objc ()); + c_parser_objc_synchronized_statement (parser); + break; + default: + goto expr_stmt; + } + break; + case CPP_SEMICOLON: + c_parser_consume_token (parser); + break; + case CPP_CLOSE_PAREN: + case CPP_CLOSE_SQUARE: + /* Avoid infinite loop in error recovery: + c_parser_skip_until_found stops at a closing nesting + delimiter without consuming it, but here we need to consume + it to proceed further. */ + c_parser_error (parser, "expected statement"); + c_parser_consume_token (parser); + break; + case CPP_PRAGMA: + c_parser_pragma (parser, pragma_stmt); + break; + default: + expr_stmt: + stmt = c_finish_expr_stmt (loc, c_parser_expression_conv (parser).value); + expect_semicolon: + c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>"); + break; + } + /* Two cases cannot and do not have line numbers associated: If stmt + is degenerate, such as "2;", then stmt is an INTEGER_CST, which + cannot hold line numbers. But that's OK because the statement + will either be changed to a MODIFY_EXPR during gimplification of + the statement expr, or discarded. If stmt was compound, but + without new variables, we will have skipped the creation of a + BIND and will have a bare STATEMENT_LIST. But that's OK because + (recursively) all of the component statements should already have + line numbers assigned. ??? Can we discard no-op statements + earlier? */ + if (CAN_HAVE_LOCATION_P (stmt) + && EXPR_LOCATION (stmt) == UNKNOWN_LOCATION) + SET_EXPR_LOCATION (stmt, loc); + + parser->in_if_block = in_if_block; +} + +/* Parse the condition from an if, do, while or for statements. */ + +static tree +c_parser_condition (c_parser *parser) +{ + location_t loc = c_parser_peek_token (parser)->location; + tree cond; + cond = c_parser_expression_conv (parser).value; + cond = c_objc_common_truthvalue_conversion (loc, cond); + cond = c_fully_fold (cond, false, NULL); + if (warn_sequence_point) + verify_sequence_points (cond); + return cond; +} + +/* Parse a parenthesized condition from an if, do or while statement. + + condition: + ( expression ) +*/ +static tree +c_parser_paren_condition (c_parser *parser) +{ + tree cond; + if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) + return error_mark_node; + cond = c_parser_condition (parser); + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); + return cond; +} + +/* Parse a statement which is a block in C99. */ + +static tree +c_parser_c99_block_statement (c_parser *parser) +{ + tree block = c_begin_compound_stmt (flag_isoc99); + location_t loc = c_parser_peek_token (parser)->location; + c_parser_statement (parser); + return c_end_compound_stmt (loc, block, flag_isoc99); +} + +/* Parse the body of an if statement. This is just parsing a + statement but (a) it is a block in C99, (b) we track whether the + body is an if statement for the sake of -Wparentheses warnings, (c) + we handle an empty body specially for the sake of -Wempty-body + warnings, and (d) we call parser_compound_statement directly + because c_parser_statement_after_labels resets + parser->in_if_block. */ + +static tree +c_parser_if_body (c_parser *parser, bool *if_p) +{ + tree block = c_begin_compound_stmt (flag_isoc99); + location_t body_loc = c_parser_peek_token (parser)->location; + while (c_parser_next_token_is_keyword (parser, RID_CASE) + || c_parser_next_token_is_keyword (parser, RID_DEFAULT) + || (c_parser_next_token_is (parser, CPP_NAME) + && c_parser_peek_2nd_token (parser)->type == CPP_COLON)) + c_parser_label (parser); + *if_p = c_parser_next_token_is_keyword (parser, RID_IF); + if (c_parser_next_token_is (parser, CPP_SEMICOLON)) + { + location_t loc = c_parser_peek_token (parser)->location; + add_stmt (build_empty_stmt (loc)); + c_parser_consume_token (parser); + if (!c_parser_next_token_is_keyword (parser, RID_ELSE)) + warning_at (loc, OPT_Wempty_body, + "suggest braces around empty body in an %<if%> statement"); + } + else if (c_parser_next_token_is (parser, CPP_OPEN_BRACE)) + add_stmt (c_parser_compound_statement (parser)); + else + c_parser_statement_after_labels (parser); + return c_end_compound_stmt (body_loc, block, flag_isoc99); +} + +/* Parse the else body of an if statement. This is just parsing a + statement but (a) it is a block in C99, (b) we handle an empty body + specially for the sake of -Wempty-body warnings. */ + +static tree +c_parser_else_body (c_parser *parser) +{ + location_t else_loc = c_parser_peek_token (parser)->location; + tree block = c_begin_compound_stmt (flag_isoc99); + while (c_parser_next_token_is_keyword (parser, RID_CASE) + || c_parser_next_token_is_keyword (parser, RID_DEFAULT) + || (c_parser_next_token_is (parser, CPP_NAME) + && c_parser_peek_2nd_token (parser)->type == CPP_COLON)) + c_parser_label (parser); + if (c_parser_next_token_is (parser, CPP_SEMICOLON)) + { + location_t loc = c_parser_peek_token (parser)->location; + warning_at (loc, + OPT_Wempty_body, + "suggest braces around empty body in an %<else%> statement"); + add_stmt (build_empty_stmt (loc)); + c_parser_consume_token (parser); + } + else + c_parser_statement_after_labels (parser); + return c_end_compound_stmt (else_loc, block, flag_isoc99); +} + +/* Parse an if statement (C90 6.6.4, C99 6.8.4). + + if-statement: + if ( expression ) statement + if ( expression ) statement else statement +*/ + +static void +c_parser_if_statement (c_parser *parser) +{ + tree block; + location_t loc; + tree cond; + bool first_if = false; + tree first_body, second_body; + bool in_if_block; + + gcc_assert (c_parser_next_token_is_keyword (parser, RID_IF)); + c_parser_consume_token (parser); + block = c_begin_compound_stmt (flag_isoc99); + loc = c_parser_peek_token (parser)->location; + cond = c_parser_paren_condition (parser); + in_if_block = parser->in_if_block; + parser->in_if_block = true; + first_body = c_parser_if_body (parser, &first_if); + parser->in_if_block = in_if_block; + if (c_parser_next_token_is_keyword (parser, RID_ELSE)) + { + c_parser_consume_token (parser); + second_body = c_parser_else_body (parser); + } + else + second_body = NULL_TREE; + c_finish_if_stmt (loc, cond, first_body, second_body, first_if); + add_stmt (c_end_compound_stmt (loc, block, flag_isoc99)); +} + +/* Parse a switch statement (C90 6.6.4, C99 6.8.4). + + switch-statement: + switch (expression) statement +*/ + +static void +c_parser_switch_statement (c_parser *parser) +{ + tree block, expr, body, save_break; + location_t switch_loc = c_parser_peek_token (parser)->location; + location_t switch_cond_loc; + gcc_assert (c_parser_next_token_is_keyword (parser, RID_SWITCH)); + c_parser_consume_token (parser); + block = c_begin_compound_stmt (flag_isoc99); + if (c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) + { + switch_cond_loc = c_parser_peek_token (parser)->location; + expr = c_parser_expression (parser).value; + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); + } + else + { + switch_cond_loc = UNKNOWN_LOCATION; + expr = error_mark_node; + } + c_start_case (switch_loc, switch_cond_loc, expr); + save_break = c_break_label; + c_break_label = NULL_TREE; + body = c_parser_c99_block_statement (parser); + c_finish_case (body); + if (c_break_label) + { + location_t here = c_parser_peek_token (parser)->location; + tree t = build1 (LABEL_EXPR, void_type_node, c_break_label); + SET_EXPR_LOCATION (t, here); + add_stmt (t); + } + c_break_label = save_break; + add_stmt (c_end_compound_stmt (switch_loc, block, flag_isoc99)); +} + +/* Parse a while statement (C90 6.6.5, C99 6.8.5). + + while-statement: + while (expression) statement +*/ + +static void +c_parser_while_statement (c_parser *parser) +{ + tree block, cond, body, save_break, save_cont; + location_t loc; + gcc_assert (c_parser_next_token_is_keyword (parser, RID_WHILE)); + c_parser_consume_token (parser); + block = c_begin_compound_stmt (flag_isoc99); + loc = c_parser_peek_token (parser)->location; + cond = c_parser_paren_condition (parser); + save_break = c_break_label; + c_break_label = NULL_TREE; + save_cont = c_cont_label; + c_cont_label = NULL_TREE; + body = c_parser_c99_block_statement (parser); + c_finish_loop (loc, cond, NULL, body, c_break_label, c_cont_label, true); + add_stmt (c_end_compound_stmt (loc, block, flag_isoc99)); + c_break_label = save_break; + c_cont_label = save_cont; +} + +/* Parse a do statement (C90 6.6.5, C99 6.8.5). + + do-statement: + do statement while ( expression ) ; +*/ + +static void +c_parser_do_statement (c_parser *parser) +{ + tree block, cond, body, save_break, save_cont, new_break, new_cont; + location_t loc; + gcc_assert (c_parser_next_token_is_keyword (parser, RID_DO)); + c_parser_consume_token (parser); + if (c_parser_next_token_is (parser, CPP_SEMICOLON)) + warning_at (c_parser_peek_token (parser)->location, + OPT_Wempty_body, + "suggest braces around empty body in %<do%> statement"); + block = c_begin_compound_stmt (flag_isoc99); + loc = c_parser_peek_token (parser)->location; + save_break = c_break_label; + c_break_label = NULL_TREE; + save_cont = c_cont_label; + c_cont_label = NULL_TREE; + body = c_parser_c99_block_statement (parser); + c_parser_require_keyword (parser, RID_WHILE, "expected %<while%>"); + new_break = c_break_label; + c_break_label = save_break; + new_cont = c_cont_label; + c_cont_label = save_cont; + cond = c_parser_paren_condition (parser); + if (!c_parser_require (parser, CPP_SEMICOLON, "expected %<;%>")) + c_parser_skip_to_end_of_block_or_statement (parser); + c_finish_loop (loc, cond, NULL, body, new_break, new_cont, false); + add_stmt (c_end_compound_stmt (loc, block, flag_isoc99)); +} + +/* Parse a for statement (C90 6.6.5, C99 6.8.5). + + for-statement: + for ( expression[opt] ; expression[opt] ; expression[opt] ) statement + for ( nested-declaration expression[opt] ; expression[opt] ) statement + + The form with a declaration is new in C99. + + ??? In accordance with the old parser, the declaration may be a + nested function, which is then rejected in check_for_loop_decls, + but does it make any sense for this to be included in the grammar? + Note in particular that the nested function does not include a + trailing ';', whereas the "declaration" production includes one. + Also, can we reject bad declarations earlier and cheaper than + check_for_loop_decls? + + In Objective-C, there are two additional variants: + + foreach-statement: + for ( expression in expresssion ) statement + for ( declaration in expression ) statement + + This is inconsistent with C, because the second variant is allowed + even if c99 is not enabled. + + The rest of the comment documents these Objective-C foreach-statement. + + Here is the canonical example of the first variant: + for (object in array) { do something with object } + we call the first expression ("object") the "object_expression" and + the second expression ("array") the "collection_expression". + object_expression must be an lvalue of type "id" (a generic Objective-C + object) because the loop works by assigning to object_expression the + various objects from the collection_expression. collection_expression + must evaluate to something of type "id" which responds to the method + countByEnumeratingWithState:objects:count:. + + The canonical example of the second variant is: + for (id object in array) { do something with object } + which is completely equivalent to + { + id object; + for (object in array) { do something with object } + } + Note that initizializing 'object' in some way (eg, "for ((object = + xxx) in array) { do something with object }") is possibly + technically valid, but completely pointless as 'object' will be + assigned to something else as soon as the loop starts. We should + most likely reject it (TODO). + + The beginning of the Objective-C foreach-statement looks exactly + like the beginning of the for-statement, and we can tell it is a + foreach-statement only because the initial declaration or + expression is terminated by 'in' instead of ';'. +*/ + +static void +c_parser_for_statement (c_parser *parser) +{ + tree block, cond, incr, save_break, save_cont, body; + /* The following are only used when parsing an ObjC foreach statement. */ + tree object_expression; + /* Silence the bogus uninitialized warning. */ + tree collection_expression = NULL; + location_t loc = c_parser_peek_token (parser)->location; + location_t for_loc = c_parser_peek_token (parser)->location; + bool is_foreach_statement = false; + gcc_assert (c_parser_next_token_is_keyword (parser, RID_FOR)); + c_parser_consume_token (parser); + /* Open a compound statement in Objective-C as well, just in case this is + as foreach expression. */ + block = c_begin_compound_stmt (flag_isoc99 || c_dialect_objc ()); + cond = error_mark_node; + incr = error_mark_node; + if (c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) + { + /* Parse the initialization declaration or expression. */ + object_expression = error_mark_node; + parser->objc_could_be_foreach_context = c_dialect_objc (); + if (c_parser_next_token_is (parser, CPP_SEMICOLON)) + { + parser->objc_could_be_foreach_context = false; + c_parser_consume_token (parser); + c_finish_expr_stmt (loc, NULL_TREE); + } + else if (c_parser_next_tokens_start_declaration (parser)) + { + c_parser_declaration_or_fndef (parser, true, true, true, true, true, + &object_expression); + parser->objc_could_be_foreach_context = false; + + if (c_parser_next_token_is_keyword (parser, RID_IN)) + { + c_parser_consume_token (parser); + is_foreach_statement = true; + if (check_for_loop_decls (for_loc, true) == NULL_TREE) + c_parser_error (parser, "multiple iterating variables in fast enumeration"); + } + else + check_for_loop_decls (for_loc, flag_isoc99); + } + else if (c_parser_next_token_is_keyword (parser, RID_EXTENSION)) + { + /* __extension__ can start a declaration, but is also an + unary operator that can start an expression. Consume all + but the last of a possible series of __extension__ to + determine which. */ + while (c_parser_peek_2nd_token (parser)->type == CPP_KEYWORD + && (c_parser_peek_2nd_token (parser)->keyword + == RID_EXTENSION)) + c_parser_consume_token (parser); + if (c_token_starts_declaration (c_parser_peek_2nd_token (parser))) + { + int ext; + ext = disable_extension_diagnostics (); + c_parser_consume_token (parser); + c_parser_declaration_or_fndef (parser, true, true, true, true, + true, &object_expression); + parser->objc_could_be_foreach_context = false; + + restore_extension_diagnostics (ext); + if (c_parser_next_token_is_keyword (parser, RID_IN)) + { + c_parser_consume_token (parser); + is_foreach_statement = true; + if (check_for_loop_decls (for_loc, true) == NULL_TREE) + c_parser_error (parser, "multiple iterating variables in fast enumeration"); + } + else + check_for_loop_decls (for_loc, flag_isoc99); + } + else + goto init_expr; + } + else + { + init_expr: + { + tree init_expression; + init_expression = c_parser_expression (parser).value; + parser->objc_could_be_foreach_context = false; + if (c_parser_next_token_is_keyword (parser, RID_IN)) + { + c_parser_consume_token (parser); + is_foreach_statement = true; + if (! lvalue_p (init_expression)) + c_parser_error (parser, "invalid iterating variable in fast enumeration"); + object_expression = c_fully_fold (init_expression, false, NULL); + } + else + { + c_finish_expr_stmt (loc, init_expression); + c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>"); + } + } + } + /* Parse the loop condition. In the case of a foreach + statement, there is no loop condition. */ + gcc_assert (!parser->objc_could_be_foreach_context); + if (!is_foreach_statement) + { + if (c_parser_next_token_is (parser, CPP_SEMICOLON)) + { + c_parser_consume_token (parser); + cond = NULL_TREE; + } + else + { + cond = c_parser_condition (parser); + c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>"); + } + } + /* Parse the increment expression (the third expression in a + for-statement). In the case of a foreach-statement, this is + the expression that follows the 'in'. */ + if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN)) + { + if (is_foreach_statement) + { + c_parser_error (parser, "missing collection in fast enumeration"); + collection_expression = error_mark_node; + } + else + incr = c_process_expr_stmt (loc, NULL_TREE); + } + else + { + if (is_foreach_statement) + collection_expression = c_fully_fold (c_parser_expression (parser).value, + false, NULL); + else + incr = c_process_expr_stmt (loc, c_parser_expression (parser).value); + } + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); + } + save_break = c_break_label; + c_break_label = NULL_TREE; + save_cont = c_cont_label; + c_cont_label = NULL_TREE; + body = c_parser_c99_block_statement (parser); + if (is_foreach_statement) + objc_finish_foreach_loop (loc, object_expression, collection_expression, body, c_break_label, c_cont_label); + else + c_finish_loop (loc, cond, incr, body, c_break_label, c_cont_label, true); + add_stmt (c_end_compound_stmt (loc, block, flag_isoc99 || c_dialect_objc ())); + c_break_label = save_break; + c_cont_label = save_cont; +} + +/* Parse an asm statement, a GNU extension. This is a full-blown asm + statement with inputs, outputs, clobbers, and volatile tag + allowed. + + asm-statement: + asm type-qualifier[opt] ( asm-argument ) ; + asm type-qualifier[opt] goto ( asm-goto-argument ) ; + + asm-argument: + asm-string-literal + asm-string-literal : asm-operands[opt] + asm-string-literal : asm-operands[opt] : asm-operands[opt] + asm-string-literal : asm-operands[opt] : asm-operands[opt] : asm-clobbers[opt] + + asm-goto-argument: + asm-string-literal : : asm-operands[opt] : asm-clobbers[opt] \ + : asm-goto-operands + + Qualifiers other than volatile are accepted in the syntax but + warned for. */ + +static tree +c_parser_asm_statement (c_parser *parser) +{ + tree quals, str, outputs, inputs, clobbers, labels, ret; + bool simple, is_goto; + location_t asm_loc = c_parser_peek_token (parser)->location; + int section, nsections; + + gcc_assert (c_parser_next_token_is_keyword (parser, RID_ASM)); + c_parser_consume_token (parser); + if (c_parser_next_token_is_keyword (parser, RID_VOLATILE)) + { + quals = c_parser_peek_token (parser)->value; + c_parser_consume_token (parser); + } + else if (c_parser_next_token_is_keyword (parser, RID_CONST) + || c_parser_next_token_is_keyword (parser, RID_RESTRICT)) + { + warning_at (c_parser_peek_token (parser)->location, + 0, + "%E qualifier ignored on asm", + c_parser_peek_token (parser)->value); + quals = NULL_TREE; + c_parser_consume_token (parser); + } + else + quals = NULL_TREE; + + is_goto = false; + if (c_parser_next_token_is_keyword (parser, RID_GOTO)) + { + c_parser_consume_token (parser); + is_goto = true; + } + + /* ??? Follow the C++ parser rather than using the + lex_untranslated_string kludge. */ + parser->lex_untranslated_string = true; + ret = NULL; + + if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) + goto error; + + str = c_parser_asm_string_literal (parser); + if (str == NULL_TREE) + goto error_close_paren; + + simple = true; + outputs = NULL_TREE; + inputs = NULL_TREE; + clobbers = NULL_TREE; + labels = NULL_TREE; + + if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN) && !is_goto) + goto done_asm; + + /* Parse each colon-delimited section of operands. */ + nsections = 3 + is_goto; + for (section = 0; section < nsections; ++section) + { + if (!c_parser_require (parser, CPP_COLON, + is_goto + ? "expected %<:%>" + : "expected %<:%> or %<)%>")) + goto error_close_paren; + + /* Once past any colon, we're no longer a simple asm. */ + simple = false; + + if ((!c_parser_next_token_is (parser, CPP_COLON) + && !c_parser_next_token_is (parser, CPP_CLOSE_PAREN)) + || section == 3) + switch (section) + { + case 0: + /* For asm goto, we don't allow output operands, but reserve + the slot for a future extension that does allow them. */ + if (!is_goto) + outputs = c_parser_asm_operands (parser, false); + break; + case 1: + inputs = c_parser_asm_operands (parser, true); + break; + case 2: + clobbers = c_parser_asm_clobbers (parser); + break; + case 3: + labels = c_parser_asm_goto_operands (parser); + break; + default: + gcc_unreachable (); + } + + if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN) && !is_goto) + goto done_asm; + } + + done_asm: + if (!c_parser_require (parser, CPP_CLOSE_PAREN, "expected %<)%>")) + { + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL); + goto error; + } + + if (!c_parser_require (parser, CPP_SEMICOLON, "expected %<;%>")) + c_parser_skip_to_end_of_block_or_statement (parser); + + ret = build_asm_stmt (quals, build_asm_expr (asm_loc, str, outputs, inputs, + clobbers, labels, simple)); + + error: + parser->lex_untranslated_string = false; + return ret; + + error_close_paren: + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL); + goto error; +} + +/* Parse asm operands, a GNU extension. If CONVERT_P (for inputs but + not outputs), apply the default conversion of functions and arrays + to pointers. + + asm-operands: + asm-operand + asm-operands , asm-operand + + asm-operand: + asm-string-literal ( expression ) + [ identifier ] asm-string-literal ( expression ) +*/ + +static tree +c_parser_asm_operands (c_parser *parser, bool convert_p) +{ + tree list = NULL_TREE; + location_t loc; + while (true) + { + tree name, str; + struct c_expr expr; + if (c_parser_next_token_is (parser, CPP_OPEN_SQUARE)) + { + c_parser_consume_token (parser); + if (c_parser_next_token_is (parser, CPP_NAME)) + { + tree id = c_parser_peek_token (parser)->value; + c_parser_consume_token (parser); + name = build_string (IDENTIFIER_LENGTH (id), + IDENTIFIER_POINTER (id)); + } + else + { + c_parser_error (parser, "expected identifier"); + c_parser_skip_until_found (parser, CPP_CLOSE_SQUARE, NULL); + return NULL_TREE; + } + c_parser_skip_until_found (parser, CPP_CLOSE_SQUARE, + "expected %<]%>"); + } + else + name = NULL_TREE; + str = c_parser_asm_string_literal (parser); + if (str == NULL_TREE) + return NULL_TREE; + parser->lex_untranslated_string = false; + if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) + { + parser->lex_untranslated_string = true; + return NULL_TREE; + } + loc = c_parser_peek_token (parser)->location; + expr = c_parser_expression (parser); + mark_exp_read (expr.value); + if (convert_p) + expr = default_function_array_conversion (loc, expr); + expr.value = c_fully_fold (expr.value, false, NULL); + parser->lex_untranslated_string = true; + if (!c_parser_require (parser, CPP_CLOSE_PAREN, "expected %<)%>")) + { + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL); + return NULL_TREE; + } + list = chainon (list, build_tree_list (build_tree_list (name, str), + expr.value)); + if (c_parser_next_token_is (parser, CPP_COMMA)) + c_parser_consume_token (parser); + else + break; + } + return list; +} + +/* Parse asm clobbers, a GNU extension. + + asm-clobbers: + asm-string-literal + asm-clobbers , asm-string-literal +*/ + +static tree +c_parser_asm_clobbers (c_parser *parser) +{ + tree list = NULL_TREE; + while (true) + { + tree str = c_parser_asm_string_literal (parser); + if (str) + list = tree_cons (NULL_TREE, str, list); + else + return NULL_TREE; + if (c_parser_next_token_is (parser, CPP_COMMA)) + c_parser_consume_token (parser); + else + break; + } + return list; +} + +/* Parse asm goto labels, a GNU extension. + + asm-goto-operands: + identifier + asm-goto-operands , identifier +*/ + +static tree +c_parser_asm_goto_operands (c_parser *parser) +{ + tree list = NULL_TREE; + while (true) + { + tree name, label; + + if (c_parser_next_token_is (parser, CPP_NAME)) + { + c_token *tok = c_parser_peek_token (parser); + name = tok->value; + label = lookup_label_for_goto (tok->location, name); + c_parser_consume_token (parser); + TREE_USED (label) = 1; + } + else + { + c_parser_error (parser, "expected identifier"); + return NULL_TREE; + } + + name = build_string (IDENTIFIER_LENGTH (name), + IDENTIFIER_POINTER (name)); + list = tree_cons (name, label, list); + if (c_parser_next_token_is (parser, CPP_COMMA)) + c_parser_consume_token (parser); + else + return nreverse (list); + } +} + +/* Parse an expression other than a compound expression; that is, an + assignment expression (C90 6.3.16, C99 6.5.16). If AFTER is not + NULL then it is an Objective-C message expression which is the + primary-expression starting the expression as an initializer. + + assignment-expression: + conditional-expression + unary-expression assignment-operator assignment-expression + + assignment-operator: one of + = *= /= %= += -= <<= >>= &= ^= |= + + In GNU C we accept any conditional expression on the LHS and + diagnose the invalid lvalue rather than producing a syntax + error. */ + +static struct c_expr +c_parser_expr_no_commas (c_parser *parser, struct c_expr *after) +{ + struct c_expr lhs, rhs, ret; + enum tree_code code; + location_t op_location, exp_location; + gcc_assert (!after || c_dialect_objc ()); + lhs = c_parser_conditional_expression (parser, after); + op_location = c_parser_peek_token (parser)->location; + switch (c_parser_peek_token (parser)->type) + { + case CPP_EQ: + code = NOP_EXPR; + break; + case CPP_MULT_EQ: + code = MULT_EXPR; + break; + case CPP_DIV_EQ: + code = TRUNC_DIV_EXPR; + break; + case CPP_MOD_EQ: + code = TRUNC_MOD_EXPR; + break; + case CPP_PLUS_EQ: + code = PLUS_EXPR; + break; + case CPP_MINUS_EQ: + code = MINUS_EXPR; + break; + case CPP_LSHIFT_EQ: + code = LSHIFT_EXPR; + break; + case CPP_RSHIFT_EQ: + code = RSHIFT_EXPR; + break; + case CPP_AND_EQ: + code = BIT_AND_EXPR; + break; + case CPP_XOR_EQ: + code = BIT_XOR_EXPR; + break; + case CPP_OR_EQ: + code = BIT_IOR_EXPR; + break; + default: + return lhs; + } + c_parser_consume_token (parser); + exp_location = c_parser_peek_token (parser)->location; + rhs = c_parser_expr_no_commas (parser, NULL); + rhs = default_function_array_read_conversion (exp_location, rhs); + ret.value = build_modify_expr (op_location, lhs.value, lhs.original_type, + code, exp_location, rhs.value, + rhs.original_type); + if (code == NOP_EXPR) + ret.original_code = MODIFY_EXPR; + else + { + TREE_NO_WARNING (ret.value) = 1; + ret.original_code = ERROR_MARK; + } + ret.original_type = NULL; + return ret; +} + +/* Parse a conditional expression (C90 6.3.15, C99 6.5.15). If AFTER + is not NULL then it is an Objective-C message expression which is + the primary-expression starting the expression as an initializer. + + conditional-expression: + logical-OR-expression + logical-OR-expression ? expression : conditional-expression + + GNU extensions: + + conditional-expression: + logical-OR-expression ? : conditional-expression +*/ + +static struct c_expr +c_parser_conditional_expression (c_parser *parser, struct c_expr *after) +{ + struct c_expr cond, exp1, exp2, ret; + location_t cond_loc, colon_loc, middle_loc; + + gcc_assert (!after || c_dialect_objc ()); + + cond = c_parser_binary_expression (parser, after, PREC_NONE); + + if (c_parser_next_token_is_not (parser, CPP_QUERY)) + return cond; + cond_loc = c_parser_peek_token (parser)->location; + cond = default_function_array_read_conversion (cond_loc, cond); + c_parser_consume_token (parser); + if (c_parser_next_token_is (parser, CPP_COLON)) + { + tree eptype = NULL_TREE; + + middle_loc = c_parser_peek_token (parser)->location; + pedwarn (middle_loc, OPT_Wpedantic, + "ISO C forbids omitting the middle term of a ?: expression"); + warn_for_omitted_condop (middle_loc, cond.value); + if (TREE_CODE (cond.value) == EXCESS_PRECISION_EXPR) + { + eptype = TREE_TYPE (cond.value); + cond.value = TREE_OPERAND (cond.value, 0); + } + /* Make sure first operand is calculated only once. */ + exp1.value = c_save_expr (default_conversion (cond.value)); + if (eptype) + exp1.value = build1 (EXCESS_PRECISION_EXPR, eptype, exp1.value); + exp1.original_type = NULL; + cond.value = c_objc_common_truthvalue_conversion (cond_loc, exp1.value); + c_inhibit_evaluation_warnings += cond.value == truthvalue_true_node; + } + else + { + cond.value + = c_objc_common_truthvalue_conversion + (cond_loc, default_conversion (cond.value)); + c_inhibit_evaluation_warnings += cond.value == truthvalue_false_node; + exp1 = c_parser_expression_conv (parser); + mark_exp_read (exp1.value); + c_inhibit_evaluation_warnings += + ((cond.value == truthvalue_true_node) + - (cond.value == truthvalue_false_node)); + } + + colon_loc = c_parser_peek_token (parser)->location; + if (!c_parser_require (parser, CPP_COLON, "expected %<:%>")) + { + c_inhibit_evaluation_warnings -= cond.value == truthvalue_true_node; + ret.value = error_mark_node; + ret.original_code = ERROR_MARK; + ret.original_type = NULL; + return ret; + } + { + location_t exp2_loc = c_parser_peek_token (parser)->location; + exp2 = c_parser_conditional_expression (parser, NULL); + exp2 = default_function_array_read_conversion (exp2_loc, exp2); + } + c_inhibit_evaluation_warnings -= cond.value == truthvalue_true_node; + ret.value = build_conditional_expr (colon_loc, cond.value, + cond.original_code == C_MAYBE_CONST_EXPR, + exp1.value, exp1.original_type, + exp2.value, exp2.original_type); + ret.original_code = ERROR_MARK; + if (exp1.value == error_mark_node || exp2.value == error_mark_node) + ret.original_type = NULL; + else + { + tree t1, t2; + + /* If both sides are enum type, the default conversion will have + made the type of the result be an integer type. We want to + remember the enum types we started with. */ + t1 = exp1.original_type ? exp1.original_type : TREE_TYPE (exp1.value); + t2 = exp2.original_type ? exp2.original_type : TREE_TYPE (exp2.value); + ret.original_type = ((t1 != error_mark_node + && t2 != error_mark_node + && (TYPE_MAIN_VARIANT (t1) + == TYPE_MAIN_VARIANT (t2))) + ? t1 + : NULL); + } + return ret; +} + +/* Parse a binary expression; that is, a logical-OR-expression (C90 + 6.3.5-6.3.14, C99 6.5.5-6.5.14). If AFTER is not NULL then it is + an Objective-C message expression which is the primary-expression + starting the expression as an initializer. PREC is the starting + precedence, usually PREC_NONE. + + multiplicative-expression: + cast-expression + multiplicative-expression * cast-expression + multiplicative-expression / cast-expression + multiplicative-expression % cast-expression + + additive-expression: + multiplicative-expression + additive-expression + multiplicative-expression + additive-expression - multiplicative-expression + + shift-expression: + additive-expression + shift-expression << additive-expression + shift-expression >> additive-expression + + relational-expression: + shift-expression + relational-expression < shift-expression + relational-expression > shift-expression + relational-expression <= shift-expression + relational-expression >= shift-expression + + equality-expression: + relational-expression + equality-expression == relational-expression + equality-expression != relational-expression + + AND-expression: + equality-expression + AND-expression & equality-expression + + exclusive-OR-expression: + AND-expression + exclusive-OR-expression ^ AND-expression + + inclusive-OR-expression: + exclusive-OR-expression + inclusive-OR-expression | exclusive-OR-expression + + logical-AND-expression: + inclusive-OR-expression + logical-AND-expression && inclusive-OR-expression + + logical-OR-expression: + logical-AND-expression + logical-OR-expression || logical-AND-expression +*/ + +static struct c_expr +c_parser_binary_expression (c_parser *parser, struct c_expr *after, + enum c_parser_prec prec) +{ + /* A binary expression is parsed using operator-precedence parsing, + with the operands being cast expressions. All the binary + operators are left-associative. Thus a binary expression is of + form: + + E0 op1 E1 op2 E2 ... + + which we represent on a stack. On the stack, the precedence + levels are strictly increasing. When a new operator is + encountered of higher precedence than that at the top of the + stack, it is pushed; its LHS is the top expression, and its RHS + is everything parsed until it is popped. When a new operator is + encountered with precedence less than or equal to that at the top + of the stack, triples E[i-1] op[i] E[i] are popped and replaced + by the result of the operation until the operator at the top of + the stack has lower precedence than the new operator or there is + only one element on the stack; then the top expression is the LHS + of the new operator. In the case of logical AND and OR + expressions, we also need to adjust c_inhibit_evaluation_warnings + as appropriate when the operators are pushed and popped. */ + + struct { + /* The expression at this stack level. */ + struct c_expr expr; + /* The precedence of the operator on its left, PREC_NONE at the + bottom of the stack. */ + enum c_parser_prec prec; + /* The operation on its left. */ + enum tree_code op; + /* The source location of this operation. */ + location_t loc; + } stack[NUM_PRECS]; + int sp; + /* Location of the binary operator. */ + location_t binary_loc = UNKNOWN_LOCATION; /* Quiet warning. */ +#define POP \ + do { \ + switch (stack[sp].op) \ + { \ + case TRUTH_ANDIF_EXPR: \ + c_inhibit_evaluation_warnings -= (stack[sp - 1].expr.value \ + == truthvalue_false_node); \ + break; \ + case TRUTH_ORIF_EXPR: \ + c_inhibit_evaluation_warnings -= (stack[sp - 1].expr.value \ + == truthvalue_true_node); \ + break; \ + default: \ + break; \ + } \ + stack[sp - 1].expr \ + = default_function_array_read_conversion (stack[sp - 1].loc, \ + stack[sp - 1].expr); \ + stack[sp].expr \ + = default_function_array_read_conversion (stack[sp].loc, \ + stack[sp].expr); \ + stack[sp - 1].expr = parser_build_binary_op (stack[sp].loc, \ + stack[sp].op, \ + stack[sp - 1].expr, \ + stack[sp].expr); \ + sp--; \ + } while (0) + gcc_assert (!after || c_dialect_objc ()); + stack[0].loc = c_parser_peek_token (parser)->location; + stack[0].expr = c_parser_cast_expression (parser, after); + stack[0].prec = prec; + sp = 0; + while (true) + { + enum c_parser_prec oprec; + enum tree_code ocode; + if (parser->error) + goto out; + switch (c_parser_peek_token (parser)->type) + { + case CPP_MULT: + oprec = PREC_MULT; + ocode = MULT_EXPR; + break; + case CPP_DIV: + oprec = PREC_MULT; + ocode = TRUNC_DIV_EXPR; + break; + case CPP_MOD: + oprec = PREC_MULT; + ocode = TRUNC_MOD_EXPR; + break; + case CPP_PLUS: + oprec = PREC_ADD; + ocode = PLUS_EXPR; + break; + case CPP_MINUS: + oprec = PREC_ADD; + ocode = MINUS_EXPR; + break; + case CPP_LSHIFT: + oprec = PREC_SHIFT; + ocode = LSHIFT_EXPR; + break; + case CPP_RSHIFT: + oprec = PREC_SHIFT; + ocode = RSHIFT_EXPR; + break; + case CPP_LESS: + oprec = PREC_REL; + ocode = LT_EXPR; + break; + case CPP_GREATER: + oprec = PREC_REL; + ocode = GT_EXPR; + break; + case CPP_LESS_EQ: + oprec = PREC_REL; + ocode = LE_EXPR; + break; + case CPP_GREATER_EQ: + oprec = PREC_REL; + ocode = GE_EXPR; + break; + case CPP_EQ_EQ: + oprec = PREC_EQ; + ocode = EQ_EXPR; + break; + case CPP_NOT_EQ: + oprec = PREC_EQ; + ocode = NE_EXPR; + break; + case CPP_AND: + oprec = PREC_BITAND; + ocode = BIT_AND_EXPR; + break; + case CPP_XOR: + oprec = PREC_BITXOR; + ocode = BIT_XOR_EXPR; + break; + case CPP_OR: + oprec = PREC_BITOR; + ocode = BIT_IOR_EXPR; + break; + case CPP_AND_AND: + oprec = PREC_LOGAND; + ocode = TRUTH_ANDIF_EXPR; + break; + case CPP_OR_OR: + oprec = PREC_LOGOR; + ocode = TRUTH_ORIF_EXPR; + break; + default: + /* Not a binary operator, so end of the binary + expression. */ + goto out; + } + binary_loc = c_parser_peek_token (parser)->location; + while (oprec <= stack[sp].prec) + { + if (sp == 0) + goto out; + POP; + } + c_parser_consume_token (parser); + switch (ocode) + { + case TRUTH_ANDIF_EXPR: + stack[sp].expr + = default_function_array_read_conversion (stack[sp].loc, + stack[sp].expr); + stack[sp].expr.value = c_objc_common_truthvalue_conversion + (stack[sp].loc, default_conversion (stack[sp].expr.value)); + c_inhibit_evaluation_warnings += (stack[sp].expr.value + == truthvalue_false_node); + break; + case TRUTH_ORIF_EXPR: + stack[sp].expr + = default_function_array_read_conversion (stack[sp].loc, + stack[sp].expr); + stack[sp].expr.value = c_objc_common_truthvalue_conversion + (stack[sp].loc, default_conversion (stack[sp].expr.value)); + c_inhibit_evaluation_warnings += (stack[sp].expr.value + == truthvalue_true_node); + break; + default: + break; + } + sp++; + stack[sp].loc = binary_loc; + stack[sp].expr = c_parser_cast_expression (parser, NULL); + stack[sp].prec = oprec; + stack[sp].op = ocode; + stack[sp].loc = binary_loc; + } + out: + while (sp > 0) + POP; + return stack[0].expr; +#undef POP +} + +/* Parse a cast expression (C90 6.3.4, C99 6.5.4). If AFTER is not + NULL then it is an Objective-C message expression which is the + primary-expression starting the expression as an initializer. + + cast-expression: + unary-expression + ( type-name ) unary-expression +*/ + +static struct c_expr +c_parser_cast_expression (c_parser *parser, struct c_expr *after) +{ + location_t cast_loc = c_parser_peek_token (parser)->location; + gcc_assert (!after || c_dialect_objc ()); + if (after) + return c_parser_postfix_expression_after_primary (parser, + cast_loc, *after); + /* If the expression begins with a parenthesized type name, it may + be either a cast or a compound literal; we need to see whether + the next character is '{' to tell the difference. If not, it is + an unary expression. Full detection of unknown typenames here + would require a 3-token lookahead. */ + if (c_parser_next_token_is (parser, CPP_OPEN_PAREN) + && c_token_starts_typename (c_parser_peek_2nd_token (parser))) + { + struct c_type_name *type_name; + struct c_expr ret; + struct c_expr expr; + c_parser_consume_token (parser); + type_name = c_parser_type_name (parser); + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); + if (type_name == NULL) + { + ret.value = error_mark_node; + ret.original_code = ERROR_MARK; + ret.original_type = NULL; + return ret; + } + + /* Save casted types in the function's used types hash table. */ + used_types_insert (type_name->specs->type); + + if (c_parser_next_token_is (parser, CPP_OPEN_BRACE)) + return c_parser_postfix_expression_after_paren_type (parser, type_name, + cast_loc); + { + location_t expr_loc = c_parser_peek_token (parser)->location; + expr = c_parser_cast_expression (parser, NULL); + expr = default_function_array_read_conversion (expr_loc, expr); + } + ret.value = c_cast_expr (cast_loc, type_name, expr.value); + ret.original_code = ERROR_MARK; + ret.original_type = NULL; + return ret; + } + else + return c_parser_unary_expression (parser); +} + +/* Parse an unary expression (C90 6.3.3, C99 6.5.3). + + unary-expression: + postfix-expression + ++ unary-expression + -- unary-expression + unary-operator cast-expression + sizeof unary-expression + sizeof ( type-name ) + + unary-operator: one of + & * + - ~ ! + + GNU extensions: + + unary-expression: + __alignof__ unary-expression + __alignof__ ( type-name ) + && identifier + + (C11 permits _Alignof with type names only.) + + unary-operator: one of + __extension__ __real__ __imag__ + + Transactional Memory: + + unary-expression: + transaction-expression + + In addition, the GNU syntax treats ++ and -- as unary operators, so + they may be applied to cast expressions with errors for non-lvalues + given later. */ + +static struct c_expr +c_parser_unary_expression (c_parser *parser) +{ + int ext; + struct c_expr ret, op; + location_t op_loc = c_parser_peek_token (parser)->location; + location_t exp_loc; + ret.original_code = ERROR_MARK; + ret.original_type = NULL; + switch (c_parser_peek_token (parser)->type) + { + case CPP_PLUS_PLUS: + c_parser_consume_token (parser); + exp_loc = c_parser_peek_token (parser)->location; + op = c_parser_cast_expression (parser, NULL); + op = default_function_array_read_conversion (exp_loc, op); + return parser_build_unary_op (op_loc, PREINCREMENT_EXPR, op); + case CPP_MINUS_MINUS: + c_parser_consume_token (parser); + exp_loc = c_parser_peek_token (parser)->location; + op = c_parser_cast_expression (parser, NULL); + op = default_function_array_read_conversion (exp_loc, op); + return parser_build_unary_op (op_loc, PREDECREMENT_EXPR, op); + case CPP_AND: + c_parser_consume_token (parser); + op = c_parser_cast_expression (parser, NULL); + mark_exp_read (op.value); + return parser_build_unary_op (op_loc, ADDR_EXPR, op); + case CPP_MULT: + c_parser_consume_token (parser); + exp_loc = c_parser_peek_token (parser)->location; + op = c_parser_cast_expression (parser, NULL); + op = default_function_array_read_conversion (exp_loc, op); + ret.value = build_indirect_ref (op_loc, op.value, RO_UNARY_STAR); + return ret; + case CPP_PLUS: + if (!c_dialect_objc () && !in_system_header) + warning_at (op_loc, + OPT_Wtraditional, + "traditional C rejects the unary plus operator"); + c_parser_consume_token (parser); + exp_loc = c_parser_peek_token (parser)->location; + op = c_parser_cast_expression (parser, NULL); + op = default_function_array_read_conversion (exp_loc, op); + return parser_build_unary_op (op_loc, CONVERT_EXPR, op); + case CPP_MINUS: + c_parser_consume_token (parser); + exp_loc = c_parser_peek_token (parser)->location; + op = c_parser_cast_expression (parser, NULL); + op = default_function_array_read_conversion (exp_loc, op); + return parser_build_unary_op (op_loc, NEGATE_EXPR, op); + case CPP_COMPL: + c_parser_consume_token (parser); + exp_loc = c_parser_peek_token (parser)->location; + op = c_parser_cast_expression (parser, NULL); + op = default_function_array_read_conversion (exp_loc, op); + return parser_build_unary_op (op_loc, BIT_NOT_EXPR, op); + case CPP_NOT: + c_parser_consume_token (parser); + exp_loc = c_parser_peek_token (parser)->location; + op = c_parser_cast_expression (parser, NULL); + op = default_function_array_read_conversion (exp_loc, op); + return parser_build_unary_op (op_loc, TRUTH_NOT_EXPR, op); + case CPP_AND_AND: + /* Refer to the address of a label as a pointer. */ + c_parser_consume_token (parser); + if (c_parser_next_token_is (parser, CPP_NAME)) + { + ret.value = finish_label_address_expr + (c_parser_peek_token (parser)->value, op_loc); + c_parser_consume_token (parser); + } + else + { + c_parser_error (parser, "expected identifier"); + ret.value = error_mark_node; + } + return ret; + case CPP_KEYWORD: + switch (c_parser_peek_token (parser)->keyword) + { + case RID_SIZEOF: + return c_parser_sizeof_expression (parser); + case RID_ALIGNOF: + return c_parser_alignof_expression (parser); + case RID_EXTENSION: + c_parser_consume_token (parser); + ext = disable_extension_diagnostics (); + ret = c_parser_cast_expression (parser, NULL); + restore_extension_diagnostics (ext); + return ret; + case RID_REALPART: + c_parser_consume_token (parser); + exp_loc = c_parser_peek_token (parser)->location; + op = c_parser_cast_expression (parser, NULL); + op = default_function_array_conversion (exp_loc, op); + return parser_build_unary_op (op_loc, REALPART_EXPR, op); + case RID_IMAGPART: + c_parser_consume_token (parser); + exp_loc = c_parser_peek_token (parser)->location; + op = c_parser_cast_expression (parser, NULL); + op = default_function_array_conversion (exp_loc, op); + return parser_build_unary_op (op_loc, IMAGPART_EXPR, op); + case RID_TRANSACTION_ATOMIC: + case RID_TRANSACTION_RELAXED: + return c_parser_transaction_expression (parser, + c_parser_peek_token (parser)->keyword); + default: + return c_parser_postfix_expression (parser); + } + default: + return c_parser_postfix_expression (parser); + } +} + +/* Parse a sizeof expression. */ + +static struct c_expr +c_parser_sizeof_expression (c_parser *parser) +{ + struct c_expr expr; + location_t expr_loc; + gcc_assert (c_parser_next_token_is_keyword (parser, RID_SIZEOF)); + c_parser_consume_token (parser); + c_inhibit_evaluation_warnings++; + in_sizeof++; + if (c_parser_next_token_is (parser, CPP_OPEN_PAREN) + && c_token_starts_typename (c_parser_peek_2nd_token (parser))) + { + /* Either sizeof ( type-name ) or sizeof unary-expression + starting with a compound literal. */ + struct c_type_name *type_name; + c_parser_consume_token (parser); + expr_loc = c_parser_peek_token (parser)->location; + type_name = c_parser_type_name (parser); + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); + if (type_name == NULL) + { + struct c_expr ret; + c_inhibit_evaluation_warnings--; + in_sizeof--; + ret.value = error_mark_node; + ret.original_code = ERROR_MARK; + ret.original_type = NULL; + return ret; + } + if (c_parser_next_token_is (parser, CPP_OPEN_BRACE)) + { + expr = c_parser_postfix_expression_after_paren_type (parser, + type_name, + expr_loc); + goto sizeof_expr; + } + /* sizeof ( type-name ). */ + c_inhibit_evaluation_warnings--; + in_sizeof--; + return c_expr_sizeof_type (expr_loc, type_name); + } + else + { + expr_loc = c_parser_peek_token (parser)->location; + expr = c_parser_unary_expression (parser); + sizeof_expr: + c_inhibit_evaluation_warnings--; + in_sizeof--; + mark_exp_read (expr.value); + if (TREE_CODE (expr.value) == COMPONENT_REF + && DECL_C_BIT_FIELD (TREE_OPERAND (expr.value, 1))) + error_at (expr_loc, "%<sizeof%> applied to a bit-field"); + return c_expr_sizeof_expr (expr_loc, expr); + } +} + +/* Parse an alignof expression. */ + +static struct c_expr +c_parser_alignof_expression (c_parser *parser) +{ + struct c_expr expr; + location_t loc = c_parser_peek_token (parser)->location; + tree alignof_spelling = c_parser_peek_token (parser)->value; + gcc_assert (c_parser_next_token_is_keyword (parser, RID_ALIGNOF)); + /* A diagnostic is not required for the use of this identifier in + the implementation namespace; only diagnose it for the C11 + spelling because of existing code using the other spellings. */ + if (!flag_isoc11 + && strcmp (IDENTIFIER_POINTER (alignof_spelling), "_Alignof") == 0) + { + if (flag_isoc99) + pedwarn (loc, OPT_Wpedantic, "ISO C99 does not support %qE", + alignof_spelling); + else + pedwarn (loc, OPT_Wpedantic, "ISO C90 does not support %qE", + alignof_spelling); + } + c_parser_consume_token (parser); + c_inhibit_evaluation_warnings++; + in_alignof++; + if (c_parser_next_token_is (parser, CPP_OPEN_PAREN) + && c_token_starts_typename (c_parser_peek_2nd_token (parser))) + { + /* Either __alignof__ ( type-name ) or __alignof__ + unary-expression starting with a compound literal. */ + location_t loc; + struct c_type_name *type_name; + struct c_expr ret; + c_parser_consume_token (parser); + loc = c_parser_peek_token (parser)->location; + type_name = c_parser_type_name (parser); + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); + if (type_name == NULL) + { + struct c_expr ret; + c_inhibit_evaluation_warnings--; + in_alignof--; + ret.value = error_mark_node; + ret.original_code = ERROR_MARK; + ret.original_type = NULL; + return ret; + } + if (c_parser_next_token_is (parser, CPP_OPEN_BRACE)) + { + expr = c_parser_postfix_expression_after_paren_type (parser, + type_name, + loc); + goto alignof_expr; + } + /* alignof ( type-name ). */ + c_inhibit_evaluation_warnings--; + in_alignof--; + ret.value = c_alignof (loc, groktypename (type_name, NULL, NULL)); + ret.original_code = ERROR_MARK; + ret.original_type = NULL; + return ret; + } + else + { + struct c_expr ret; + expr = c_parser_unary_expression (parser); + alignof_expr: + mark_exp_read (expr.value); + c_inhibit_evaluation_warnings--; + in_alignof--; + pedwarn (loc, OPT_Wpedantic, "ISO C does not allow %<%E (expression)%>", + alignof_spelling); + ret.value = c_alignof_expr (loc, expr.value); + ret.original_code = ERROR_MARK; + ret.original_type = NULL; + return ret; + } +} + +/* Helper function to read arguments of builtins which are interfaces + for the middle-end nodes like COMPLEX_EXPR, VEC_PERM_EXPR and + others. The name of the builtin is passed using BNAME parameter. + Function returns true if there were no errors while parsing and + stores the arguments in CEXPR_LIST. */ +static bool +c_parser_get_builtin_args (c_parser *parser, const char *bname, + VEC(c_expr_t,gc) **ret_cexpr_list) +{ + location_t loc = c_parser_peek_token (parser)->location; + VEC (c_expr_t,gc) *cexpr_list; + c_expr_t expr; + + *ret_cexpr_list = NULL; + if (c_parser_next_token_is_not (parser, CPP_OPEN_PAREN)) + { + error_at (loc, "cannot take address of %qs", bname); + return false; + } + + c_parser_consume_token (parser); + + if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN)) + { + c_parser_consume_token (parser); + return true; + } + + expr = c_parser_expr_no_commas (parser, NULL); + cexpr_list = VEC_alloc (c_expr_t, gc, 1); + C_EXPR_APPEND (cexpr_list, expr); + while (c_parser_next_token_is (parser, CPP_COMMA)) + { + c_parser_consume_token (parser); + expr = c_parser_expr_no_commas (parser, NULL); + C_EXPR_APPEND (cexpr_list, expr); + } + + if (!c_parser_require (parser, CPP_CLOSE_PAREN, "expected %<)%>")) + return false; + + *ret_cexpr_list = cexpr_list; + return true; +} + + +/* Parse a postfix expression (C90 6.3.1-6.3.2, C99 6.5.1-6.5.2). + + postfix-expression: + primary-expression + postfix-expression [ expression ] + postfix-expression ( argument-expression-list[opt] ) + postfix-expression . identifier + postfix-expression -> identifier + postfix-expression ++ + postfix-expression -- + ( type-name ) { initializer-list } + ( type-name ) { initializer-list , } + + argument-expression-list: + argument-expression + argument-expression-list , argument-expression + + primary-expression: + identifier + constant + string-literal + ( expression ) + + GNU extensions: + + primary-expression: + __func__ + (treated as a keyword in GNU C) + __FUNCTION__ + __PRETTY_FUNCTION__ + ( compound-statement ) + __builtin_va_arg ( assignment-expression , type-name ) + __builtin_offsetof ( type-name , offsetof-member-designator ) + __builtin_choose_expr ( assignment-expression , + assignment-expression , + assignment-expression ) + __builtin_types_compatible_p ( type-name , type-name ) + __builtin_complex ( assignment-expression , assignment-expression ) + __builtin_shuffle ( assignment-expression , assignment-expression ) + __builtin_shuffle ( assignment-expression , + assignment-expression , + assignment-expression, ) + + offsetof-member-designator: + identifier + offsetof-member-designator . identifier + offsetof-member-designator [ expression ] + + Objective-C: + + primary-expression: + [ objc-receiver objc-message-args ] + @selector ( objc-selector-arg ) + @protocol ( identifier ) + @encode ( type-name ) + objc-string-literal + Classname . identifier +*/ + +static struct c_expr +c_parser_postfix_expression (c_parser *parser) +{ + struct c_expr expr, e1; + struct c_type_name *t1, *t2; + location_t loc = c_parser_peek_token (parser)->location;; + expr.original_code = ERROR_MARK; + expr.original_type = NULL; + switch (c_parser_peek_token (parser)->type) + { + case CPP_NUMBER: + expr.value = c_parser_peek_token (parser)->value; + loc = c_parser_peek_token (parser)->location; + c_parser_consume_token (parser); + if (TREE_CODE (expr.value) == FIXED_CST + && !targetm.fixed_point_supported_p ()) + { + error_at (loc, "fixed-point types not supported for this target"); + expr.value = error_mark_node; + } + break; + case CPP_CHAR: + case CPP_CHAR16: + case CPP_CHAR32: + case CPP_WCHAR: + expr.value = c_parser_peek_token (parser)->value; + c_parser_consume_token (parser); + break; + case CPP_STRING: + case CPP_STRING16: + case CPP_STRING32: + case CPP_WSTRING: + case CPP_UTF8STRING: + expr.value = c_parser_peek_token (parser)->value; + expr.original_code = STRING_CST; + c_parser_consume_token (parser); + break; + case CPP_OBJC_STRING: + gcc_assert (c_dialect_objc ()); + expr.value + = objc_build_string_object (c_parser_peek_token (parser)->value); + c_parser_consume_token (parser); + break; + case CPP_NAME: + switch (c_parser_peek_token (parser)->id_kind) + { + case C_ID_ID: + { + tree id = c_parser_peek_token (parser)->value; + c_parser_consume_token (parser); + expr.value = build_external_ref (loc, id, + (c_parser_peek_token (parser)->type + == CPP_OPEN_PAREN), + &expr.original_type); + break; + } + case C_ID_CLASSNAME: + { + /* Here we parse the Objective-C 2.0 Class.name dot + syntax. */ + tree class_name = c_parser_peek_token (parser)->value; + tree component; + c_parser_consume_token (parser); + gcc_assert (c_dialect_objc ()); + if (!c_parser_require (parser, CPP_DOT, "expected %<.%>")) + { + expr.value = error_mark_node; + break; + } + if (c_parser_next_token_is_not (parser, CPP_NAME)) + { + c_parser_error (parser, "expected identifier"); + expr.value = error_mark_node; + break; + } + component = c_parser_peek_token (parser)->value; + c_parser_consume_token (parser); + expr.value = objc_build_class_component_ref (class_name, + component); + break; + } + default: + c_parser_error (parser, "expected expression"); + expr.value = error_mark_node; + break; + } + break; + case CPP_OPEN_PAREN: + /* A parenthesized expression, statement expression or compound + literal. */ + if (c_parser_peek_2nd_token (parser)->type == CPP_OPEN_BRACE) + { + /* A statement expression. */ + tree stmt; + location_t brace_loc; + c_parser_consume_token (parser); + brace_loc = c_parser_peek_token (parser)->location; + c_parser_consume_token (parser); + if (!building_stmt_list_p ()) + { + error_at (loc, "braced-group within expression allowed " + "only inside a function"); + parser->error = true; + c_parser_skip_until_found (parser, CPP_CLOSE_BRACE, NULL); + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL); + expr.value = error_mark_node; + break; + } + stmt = c_begin_stmt_expr (); + c_parser_compound_statement_nostart (parser); + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, + "expected %<)%>"); + pedwarn (loc, OPT_Wpedantic, + "ISO C forbids braced-groups within expressions"); + expr.value = c_finish_stmt_expr (brace_loc, stmt); + mark_exp_read (expr.value); + } + else if (c_token_starts_typename (c_parser_peek_2nd_token (parser))) + { + /* A compound literal. ??? Can we actually get here rather + than going directly to + c_parser_postfix_expression_after_paren_type from + elsewhere? */ + location_t loc; + struct c_type_name *type_name; + c_parser_consume_token (parser); + loc = c_parser_peek_token (parser)->location; + type_name = c_parser_type_name (parser); + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, + "expected %<)%>"); + if (type_name == NULL) + { + expr.value = error_mark_node; + } + else + expr = c_parser_postfix_expression_after_paren_type (parser, + type_name, + loc); + } + else + { + /* A parenthesized expression. */ + c_parser_consume_token (parser); + expr = c_parser_expression (parser); + if (TREE_CODE (expr.value) == MODIFY_EXPR) + TREE_NO_WARNING (expr.value) = 1; + if (expr.original_code != C_MAYBE_CONST_EXPR) + expr.original_code = ERROR_MARK; + /* Don't change EXPR.ORIGINAL_TYPE. */ + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, + "expected %<)%>"); + } + break; + case CPP_KEYWORD: + switch (c_parser_peek_token (parser)->keyword) + { + case RID_FUNCTION_NAME: + case RID_PRETTY_FUNCTION_NAME: + case RID_C99_FUNCTION_NAME: + expr.value = fname_decl (loc, + c_parser_peek_token (parser)->keyword, + c_parser_peek_token (parser)->value); + c_parser_consume_token (parser); + break; + case RID_VA_ARG: + c_parser_consume_token (parser); + if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) + { + expr.value = error_mark_node; + break; + } + e1 = c_parser_expr_no_commas (parser, NULL); + mark_exp_read (e1.value); + e1.value = c_fully_fold (e1.value, false, NULL); + if (!c_parser_require (parser, CPP_COMMA, "expected %<,%>")) + { + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL); + expr.value = error_mark_node; + break; + } + loc = c_parser_peek_token (parser)->location; + t1 = c_parser_type_name (parser); + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, + "expected %<)%>"); + if (t1 == NULL) + { + expr.value = error_mark_node; + } + else + { + tree type_expr = NULL_TREE; + expr.value = c_build_va_arg (loc, e1.value, + groktypename (t1, &type_expr, NULL)); + if (type_expr) + { + expr.value = build2 (C_MAYBE_CONST_EXPR, + TREE_TYPE (expr.value), type_expr, + expr.value); + C_MAYBE_CONST_EXPR_NON_CONST (expr.value) = true; + } + } + break; + case RID_OFFSETOF: + c_parser_consume_token (parser); + if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) + { + expr.value = error_mark_node; + break; + } + t1 = c_parser_type_name (parser); + if (t1 == NULL) + parser->error = true; + if (!c_parser_require (parser, CPP_COMMA, "expected %<,%>")) + gcc_assert (parser->error); + if (parser->error) + { + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL); + expr.value = error_mark_node; + break; + } + + { + tree type = groktypename (t1, NULL, NULL); + tree offsetof_ref; + if (type == error_mark_node) + offsetof_ref = error_mark_node; + else + { + offsetof_ref = build1 (INDIRECT_REF, type, null_pointer_node); + SET_EXPR_LOCATION (offsetof_ref, loc); + } + /* Parse the second argument to __builtin_offsetof. We + must have one identifier, and beyond that we want to + accept sub structure and sub array references. */ + if (c_parser_next_token_is (parser, CPP_NAME)) + { + offsetof_ref = build_component_ref + (loc, offsetof_ref, c_parser_peek_token (parser)->value); + c_parser_consume_token (parser); + while (c_parser_next_token_is (parser, CPP_DOT) + || c_parser_next_token_is (parser, + CPP_OPEN_SQUARE) + || c_parser_next_token_is (parser, + CPP_DEREF)) + { + if (c_parser_next_token_is (parser, CPP_DEREF)) + { + loc = c_parser_peek_token (parser)->location; + offsetof_ref = build_array_ref (loc, + offsetof_ref, + integer_zero_node); + goto do_dot; + } + else if (c_parser_next_token_is (parser, CPP_DOT)) + { + do_dot: + c_parser_consume_token (parser); + if (c_parser_next_token_is_not (parser, + CPP_NAME)) + { + c_parser_error (parser, "expected identifier"); + break; + } + offsetof_ref = build_component_ref + (loc, offsetof_ref, + c_parser_peek_token (parser)->value); + c_parser_consume_token (parser); + } + else + { + tree idx; + loc = c_parser_peek_token (parser)->location; + c_parser_consume_token (parser); + idx = c_parser_expression (parser).value; + idx = c_fully_fold (idx, false, NULL); + c_parser_skip_until_found (parser, CPP_CLOSE_SQUARE, + "expected %<]%>"); + offsetof_ref = build_array_ref (loc, offsetof_ref, idx); + } + } + } + else + c_parser_error (parser, "expected identifier"); + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, + "expected %<)%>"); + expr.value = fold_offsetof (offsetof_ref); + } + break; + case RID_CHOOSE_EXPR: + { + VEC (c_expr_t, gc) *cexpr_list; + c_expr_t *e1_p, *e2_p, *e3_p; + tree c; + + c_parser_consume_token (parser); + if (!c_parser_get_builtin_args (parser, + "__builtin_choose_expr", + &cexpr_list)) + { + expr.value = error_mark_node; + break; + } + + if (VEC_length (c_expr_t, cexpr_list) != 3) + { + error_at (loc, "wrong number of arguments to " + "%<__builtin_choose_expr%>"); + expr.value = error_mark_node; + break; + } + + e1_p = VEC_index (c_expr_t, cexpr_list, 0); + e2_p = VEC_index (c_expr_t, cexpr_list, 1); + e3_p = VEC_index (c_expr_t, cexpr_list, 2); + + c = e1_p->value; + mark_exp_read (e2_p->value); + mark_exp_read (e3_p->value); + if (TREE_CODE (c) != INTEGER_CST + || !INTEGRAL_TYPE_P (TREE_TYPE (c))) + error_at (loc, + "first argument to %<__builtin_choose_expr%> not" + " a constant"); + constant_expression_warning (c); + expr = integer_zerop (c) ? *e3_p : *e2_p; + break; + } + case RID_TYPES_COMPATIBLE_P: + c_parser_consume_token (parser); + if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) + { + expr.value = error_mark_node; + break; + } + t1 = c_parser_type_name (parser); + if (t1 == NULL) + { + expr.value = error_mark_node; + break; + } + if (!c_parser_require (parser, CPP_COMMA, "expected %<,%>")) + { + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL); + expr.value = error_mark_node; + break; + } + t2 = c_parser_type_name (parser); + if (t2 == NULL) + { + expr.value = error_mark_node; + break; + } + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, + "expected %<)%>"); + { + tree e1, e2; + e1 = groktypename (t1, NULL, NULL); + e2 = groktypename (t2, NULL, NULL); + if (e1 == error_mark_node || e2 == error_mark_node) + { + expr.value = error_mark_node; + break; + } + + e1 = TYPE_MAIN_VARIANT (e1); + e2 = TYPE_MAIN_VARIANT (e2); + + expr.value + = comptypes (e1, e2) ? integer_one_node : integer_zero_node; + } + break; + case RID_BUILTIN_COMPLEX: + { + VEC(c_expr_t, gc) *cexpr_list; + c_expr_t *e1_p, *e2_p; + + c_parser_consume_token (parser); + if (!c_parser_get_builtin_args (parser, + "__builtin_complex", + &cexpr_list)) + { + expr.value = error_mark_node; + break; + } + + if (VEC_length (c_expr_t, cexpr_list) != 2) + { + error_at (loc, "wrong number of arguments to " + "%<__builtin_complex%>"); + expr.value = error_mark_node; + break; + } + + e1_p = VEC_index (c_expr_t, cexpr_list, 0); + e2_p = VEC_index (c_expr_t, cexpr_list, 1); + + mark_exp_read (e1_p->value); + if (TREE_CODE (e1_p->value) == EXCESS_PRECISION_EXPR) + e1_p->value = convert (TREE_TYPE (e1_p->value), + TREE_OPERAND (e1_p->value, 0)); + mark_exp_read (e2_p->value); + if (TREE_CODE (e2_p->value) == EXCESS_PRECISION_EXPR) + e2_p->value = convert (TREE_TYPE (e2_p->value), + TREE_OPERAND (e2_p->value, 0)); + if (!SCALAR_FLOAT_TYPE_P (TREE_TYPE (e1_p->value)) + || DECIMAL_FLOAT_TYPE_P (TREE_TYPE (e1_p->value)) + || !SCALAR_FLOAT_TYPE_P (TREE_TYPE (e2_p->value)) + || DECIMAL_FLOAT_TYPE_P (TREE_TYPE (e2_p->value))) + { + error_at (loc, "%<__builtin_complex%> operand " + "not of real binary floating-point type"); + expr.value = error_mark_node; + break; + } + if (TYPE_MAIN_VARIANT (TREE_TYPE (e1_p->value)) + != TYPE_MAIN_VARIANT (TREE_TYPE (e2_p->value))) + { + error_at (loc, + "%<__builtin_complex%> operands of different types"); + expr.value = error_mark_node; + break; + } + if (!flag_isoc99) + pedwarn (loc, OPT_Wpedantic, + "ISO C90 does not support complex types"); + expr.value = build2 (COMPLEX_EXPR, + build_complex_type + (TYPE_MAIN_VARIANT + (TREE_TYPE (e1_p->value))), + e1_p->value, e2_p->value); + break; + } + case RID_BUILTIN_SHUFFLE: + { + VEC(c_expr_t,gc) *cexpr_list; + unsigned int i; + c_expr_t *p; + + c_parser_consume_token (parser); + if (!c_parser_get_builtin_args (parser, + "__builtin_shuffle", + &cexpr_list)) + { + expr.value = error_mark_node; + break; + } + + FOR_EACH_VEC_ELT (c_expr_t, cexpr_list, i, p) + mark_exp_read (p->value); + + if (VEC_length (c_expr_t, cexpr_list) == 2) + expr.value = + c_build_vec_perm_expr + (loc, VEC_index (c_expr_t, cexpr_list, 0)->value, + NULL_TREE, VEC_index (c_expr_t, cexpr_list, 1)->value); + + else if (VEC_length (c_expr_t, cexpr_list) == 3) + expr.value = + c_build_vec_perm_expr + (loc, VEC_index (c_expr_t, cexpr_list, 0)->value, + VEC_index (c_expr_t, cexpr_list, 1)->value, + VEC_index (c_expr_t, cexpr_list, 2)->value); + else + { + error_at (loc, "wrong number of arguments to " + "%<__builtin_shuffle%>"); + expr.value = error_mark_node; + } + break; + } + case RID_AT_SELECTOR: + gcc_assert (c_dialect_objc ()); + c_parser_consume_token (parser); + if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) + { + expr.value = error_mark_node; + break; + } + { + tree sel = c_parser_objc_selector_arg (parser); + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, + "expected %<)%>"); + expr.value = objc_build_selector_expr (loc, sel); + } + break; + case RID_AT_PROTOCOL: + gcc_assert (c_dialect_objc ()); + c_parser_consume_token (parser); + if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) + { + expr.value = error_mark_node; + break; + } + if (c_parser_next_token_is_not (parser, CPP_NAME)) + { + c_parser_error (parser, "expected identifier"); + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL); + expr.value = error_mark_node; + break; + } + { + tree id = c_parser_peek_token (parser)->value; + c_parser_consume_token (parser); + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, + "expected %<)%>"); + expr.value = objc_build_protocol_expr (id); + } + break; + case RID_AT_ENCODE: + /* Extension to support C-structures in the archiver. */ + gcc_assert (c_dialect_objc ()); + c_parser_consume_token (parser); + if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) + { + expr.value = error_mark_node; + break; + } + t1 = c_parser_type_name (parser); + if (t1 == NULL) + { + expr.value = error_mark_node; + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL); + break; + } + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, + "expected %<)%>"); + { + tree type = groktypename (t1, NULL, NULL); + expr.value = objc_build_encode_expr (type); + } + break; + default: + c_parser_error (parser, "expected expression"); + expr.value = error_mark_node; + break; + } + break; + case CPP_OPEN_SQUARE: + if (c_dialect_objc ()) + { + tree receiver, args; + c_parser_consume_token (parser); + receiver = c_parser_objc_receiver (parser); + args = c_parser_objc_message_args (parser); + c_parser_skip_until_found (parser, CPP_CLOSE_SQUARE, + "expected %<]%>"); + expr.value = objc_build_message_expr (receiver, args); + break; + } + /* Else fall through to report error. */ + default: + c_parser_error (parser, "expected expression"); + expr.value = error_mark_node; + break; + } + return c_parser_postfix_expression_after_primary (parser, loc, expr); +} + +/* Parse a postfix expression after a parenthesized type name: the + brace-enclosed initializer of a compound literal, possibly followed + by some postfix operators. This is separate because it is not + possible to tell until after the type name whether a cast + expression has a cast or a compound literal, or whether the operand + of sizeof is a parenthesized type name or starts with a compound + literal. TYPE_LOC is the location where TYPE_NAME starts--the + location of the first token after the parentheses around the type + name. */ + +static struct c_expr +c_parser_postfix_expression_after_paren_type (c_parser *parser, + struct c_type_name *type_name, + location_t type_loc) +{ + tree type; + struct c_expr init; + bool non_const; + struct c_expr expr; + location_t start_loc; + tree type_expr = NULL_TREE; + bool type_expr_const = true; + check_compound_literal_type (type_loc, type_name); + start_init (NULL_TREE, NULL, 0); + type = groktypename (type_name, &type_expr, &type_expr_const); + start_loc = c_parser_peek_token (parser)->location; + if (type != error_mark_node && C_TYPE_VARIABLE_SIZE (type)) + { + error_at (type_loc, "compound literal has variable size"); + type = error_mark_node; + } + init = c_parser_braced_init (parser, type, false); + finish_init (); + maybe_warn_string_init (type, init); + + if (type != error_mark_node + && !ADDR_SPACE_GENERIC_P (TYPE_ADDR_SPACE (type)) + && current_function_decl) + { + error ("compound literal qualified by address-space qualifier"); + type = error_mark_node; + } + + if (!flag_isoc99) + pedwarn (start_loc, OPT_Wpedantic, "ISO C90 forbids compound literals"); + non_const = ((init.value && TREE_CODE (init.value) == CONSTRUCTOR) + ? CONSTRUCTOR_NON_CONST (init.value) + : init.original_code == C_MAYBE_CONST_EXPR); + non_const |= !type_expr_const; + expr.value = build_compound_literal (start_loc, type, init.value, non_const); + expr.original_code = ERROR_MARK; + expr.original_type = NULL; + if (type_expr) + { + if (TREE_CODE (expr.value) == C_MAYBE_CONST_EXPR) + { + gcc_assert (C_MAYBE_CONST_EXPR_PRE (expr.value) == NULL_TREE); + C_MAYBE_CONST_EXPR_PRE (expr.value) = type_expr; + } + else + { + gcc_assert (!non_const); + expr.value = build2 (C_MAYBE_CONST_EXPR, type, + type_expr, expr.value); + } + } + return c_parser_postfix_expression_after_primary (parser, start_loc, expr); +} + +/* Parse a postfix expression after the initial primary or compound + literal; that is, parse a series of postfix operators. + + EXPR_LOC is the location of the primary expression. */ + +static struct c_expr +c_parser_postfix_expression_after_primary (c_parser *parser, + location_t expr_loc, + struct c_expr expr) +{ + struct c_expr orig_expr; + tree ident, idx; + VEC(tree,gc) *exprlist; + VEC(tree,gc) *origtypes; + while (true) + { + location_t op_loc = c_parser_peek_token (parser)->location; + switch (c_parser_peek_token (parser)->type) + { + case CPP_OPEN_SQUARE: + /* Array reference. */ + c_parser_consume_token (parser); + idx = c_parser_expression (parser).value; + c_parser_skip_until_found (parser, CPP_CLOSE_SQUARE, + "expected %<]%>"); + expr.value = build_array_ref (op_loc, expr.value, idx); + expr.original_code = ERROR_MARK; + expr.original_type = NULL; + break; + case CPP_OPEN_PAREN: + /* Function call. */ + c_parser_consume_token (parser); + if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN)) + exprlist = NULL; + else + exprlist = c_parser_expr_list (parser, true, false, &origtypes); + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, + "expected %<)%>"); + orig_expr = expr; + mark_exp_read (expr.value); + /* FIXME diagnostics: Ideally we want the FUNCNAME, not the + "(" after the FUNCNAME, which is what we have now. */ + expr.value = build_function_call_vec (op_loc, expr.value, exprlist, + origtypes); + expr.original_code = ERROR_MARK; + if (TREE_CODE (expr.value) == INTEGER_CST + && TREE_CODE (orig_expr.value) == FUNCTION_DECL + && DECL_BUILT_IN_CLASS (orig_expr.value) == BUILT_IN_NORMAL + && DECL_FUNCTION_CODE (orig_expr.value) == BUILT_IN_CONSTANT_P) + expr.original_code = C_MAYBE_CONST_EXPR; + expr.original_type = NULL; + if (exprlist != NULL) + { + release_tree_vector (exprlist); + release_tree_vector (origtypes); + } + break; + case CPP_DOT: + /* Structure element reference. */ + c_parser_consume_token (parser); + expr = default_function_array_conversion (expr_loc, expr); + if (c_parser_next_token_is (parser, CPP_NAME)) + ident = c_parser_peek_token (parser)->value; + else + { + c_parser_error (parser, "expected identifier"); + expr.value = error_mark_node; + expr.original_code = ERROR_MARK; + expr.original_type = NULL; + return expr; + } + c_parser_consume_token (parser); + expr.value = build_component_ref (op_loc, expr.value, ident); + expr.original_code = ERROR_MARK; + if (TREE_CODE (expr.value) != COMPONENT_REF) + expr.original_type = NULL; + else + { + /* Remember the original type of a bitfield. */ + tree field = TREE_OPERAND (expr.value, 1); + if (TREE_CODE (field) != FIELD_DECL) + expr.original_type = NULL; + else + expr.original_type = DECL_BIT_FIELD_TYPE (field); + } + break; + case CPP_DEREF: + /* Structure element reference. */ + c_parser_consume_token (parser); + expr = default_function_array_conversion (expr_loc, expr); + if (c_parser_next_token_is (parser, CPP_NAME)) + ident = c_parser_peek_token (parser)->value; + else + { + c_parser_error (parser, "expected identifier"); + expr.value = error_mark_node; + expr.original_code = ERROR_MARK; + expr.original_type = NULL; + return expr; + } + c_parser_consume_token (parser); + expr.value = build_component_ref (op_loc, + build_indirect_ref (op_loc, + expr.value, + RO_ARROW), + ident); + expr.original_code = ERROR_MARK; + if (TREE_CODE (expr.value) != COMPONENT_REF) + expr.original_type = NULL; + else + { + /* Remember the original type of a bitfield. */ + tree field = TREE_OPERAND (expr.value, 1); + if (TREE_CODE (field) != FIELD_DECL) + expr.original_type = NULL; + else + expr.original_type = DECL_BIT_FIELD_TYPE (field); + } + break; + case CPP_PLUS_PLUS: + /* Postincrement. */ + c_parser_consume_token (parser); + expr = default_function_array_read_conversion (expr_loc, expr); + expr.value = build_unary_op (op_loc, + POSTINCREMENT_EXPR, expr.value, 0); + expr.original_code = ERROR_MARK; + expr.original_type = NULL; + break; + case CPP_MINUS_MINUS: + /* Postdecrement. */ + c_parser_consume_token (parser); + expr = default_function_array_read_conversion (expr_loc, expr); + expr.value = build_unary_op (op_loc, + POSTDECREMENT_EXPR, expr.value, 0); + expr.original_code = ERROR_MARK; + expr.original_type = NULL; + break; + default: + return expr; + } + } +} + +/* Parse an expression (C90 6.3.17, C99 6.5.17). + + expression: + assignment-expression + expression , assignment-expression +*/ + +static struct c_expr +c_parser_expression (c_parser *parser) +{ + struct c_expr expr; + expr = c_parser_expr_no_commas (parser, NULL); + while (c_parser_next_token_is (parser, CPP_COMMA)) + { + struct c_expr next; + tree lhsval; + location_t loc = c_parser_peek_token (parser)->location; + location_t expr_loc; + c_parser_consume_token (parser); + expr_loc = c_parser_peek_token (parser)->location; + lhsval = expr.value; + while (TREE_CODE (lhsval) == COMPOUND_EXPR) + lhsval = TREE_OPERAND (lhsval, 1); + if (DECL_P (lhsval) || handled_component_p (lhsval)) + mark_exp_read (lhsval); + next = c_parser_expr_no_commas (parser, NULL); + next = default_function_array_conversion (expr_loc, next); + expr.value = build_compound_expr (loc, expr.value, next.value); + expr.original_code = COMPOUND_EXPR; + expr.original_type = next.original_type; + } + return expr; +} + +/* Parse an expression and convert functions or arrays to + pointers. */ + +static struct c_expr +c_parser_expression_conv (c_parser *parser) +{ + struct c_expr expr; + location_t loc = c_parser_peek_token (parser)->location; + expr = c_parser_expression (parser); + expr = default_function_array_conversion (loc, expr); + return expr; +} + +/* Parse a non-empty list of expressions. If CONVERT_P, convert + functions and arrays to pointers. If FOLD_P, fold the expressions. + + nonempty-expr-list: + assignment-expression + nonempty-expr-list , assignment-expression +*/ + +static VEC(tree,gc) * +c_parser_expr_list (c_parser *parser, bool convert_p, bool fold_p, + VEC(tree,gc) **p_orig_types) +{ + VEC(tree,gc) *ret; + VEC(tree,gc) *orig_types; + struct c_expr expr; + location_t loc = c_parser_peek_token (parser)->location; + + ret = make_tree_vector (); + if (p_orig_types == NULL) + orig_types = NULL; + else + orig_types = make_tree_vector (); + + expr = c_parser_expr_no_commas (parser, NULL); + if (convert_p) + expr = default_function_array_read_conversion (loc, expr); + if (fold_p) + expr.value = c_fully_fold (expr.value, false, NULL); + VEC_quick_push (tree, ret, expr.value); + if (orig_types != NULL) + VEC_quick_push (tree, orig_types, expr.original_type); + while (c_parser_next_token_is (parser, CPP_COMMA)) + { + c_parser_consume_token (parser); + loc = c_parser_peek_token (parser)->location; + expr = c_parser_expr_no_commas (parser, NULL); + if (convert_p) + expr = default_function_array_read_conversion (loc, expr); + if (fold_p) + expr.value = c_fully_fold (expr.value, false, NULL); + VEC_safe_push (tree, gc, ret, expr.value); + if (orig_types != NULL) + VEC_safe_push (tree, gc, orig_types, expr.original_type); + } + if (orig_types != NULL) + *p_orig_types = orig_types; + return ret; +} + +/* Parse Objective-C-specific constructs. */ + +/* Parse an objc-class-definition. + + objc-class-definition: + @interface identifier objc-superclass[opt] objc-protocol-refs[opt] + objc-class-instance-variables[opt] objc-methodprotolist @end + @implementation identifier objc-superclass[opt] + objc-class-instance-variables[opt] + @interface identifier ( identifier ) objc-protocol-refs[opt] + objc-methodprotolist @end + @interface identifier ( ) objc-protocol-refs[opt] + objc-methodprotolist @end + @implementation identifier ( identifier ) + + objc-superclass: + : identifier + + "@interface identifier (" must start "@interface identifier ( + identifier ) ...": objc-methodprotolist in the first production may + not start with a parenthesized identifier as a declarator of a data + definition with no declaration specifiers if the objc-superclass, + objc-protocol-refs and objc-class-instance-variables are omitted. */ + +static void +c_parser_objc_class_definition (c_parser *parser, tree attributes) +{ + bool iface_p; + tree id1; + tree superclass; + if (c_parser_next_token_is_keyword (parser, RID_AT_INTERFACE)) + iface_p = true; + else if (c_parser_next_token_is_keyword (parser, RID_AT_IMPLEMENTATION)) + iface_p = false; + else + gcc_unreachable (); + + c_parser_consume_token (parser); + if (c_parser_next_token_is_not (parser, CPP_NAME)) + { + c_parser_error (parser, "expected identifier"); + return; + } + id1 = c_parser_peek_token (parser)->value; + c_parser_consume_token (parser); + if (c_parser_next_token_is (parser, CPP_OPEN_PAREN)) + { + /* We have a category or class extension. */ + tree id2; + tree proto = NULL_TREE; + c_parser_consume_token (parser); + if (c_parser_next_token_is_not (parser, CPP_NAME)) + { + if (iface_p && c_parser_next_token_is (parser, CPP_CLOSE_PAREN)) + { + /* We have a class extension. */ + id2 = NULL_TREE; + } + else + { + c_parser_error (parser, "expected identifier or %<)%>"); + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL); + return; + } + } + else + { + id2 = c_parser_peek_token (parser)->value; + c_parser_consume_token (parser); + } + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); + if (!iface_p) + { + objc_start_category_implementation (id1, id2); + return; + } + if (c_parser_next_token_is (parser, CPP_LESS)) + proto = c_parser_objc_protocol_refs (parser); + objc_start_category_interface (id1, id2, proto, attributes); + c_parser_objc_methodprotolist (parser); + c_parser_require_keyword (parser, RID_AT_END, "expected %<@end%>"); + objc_finish_interface (); + return; + } + if (c_parser_next_token_is (parser, CPP_COLON)) + { + c_parser_consume_token (parser); + if (c_parser_next_token_is_not (parser, CPP_NAME)) + { + c_parser_error (parser, "expected identifier"); + return; + } + superclass = c_parser_peek_token (parser)->value; + c_parser_consume_token (parser); + } + else + superclass = NULL_TREE; + if (iface_p) + { + tree proto = NULL_TREE; + if (c_parser_next_token_is (parser, CPP_LESS)) + proto = c_parser_objc_protocol_refs (parser); + objc_start_class_interface (id1, superclass, proto, attributes); + } + else + objc_start_class_implementation (id1, superclass); + if (c_parser_next_token_is (parser, CPP_OPEN_BRACE)) + c_parser_objc_class_instance_variables (parser); + if (iface_p) + { + objc_continue_interface (); + c_parser_objc_methodprotolist (parser); + c_parser_require_keyword (parser, RID_AT_END, "expected %<@end%>"); + objc_finish_interface (); + } + else + { + objc_continue_implementation (); + return; + } +} + +/* Parse objc-class-instance-variables. + + objc-class-instance-variables: + { objc-instance-variable-decl-list[opt] } + + objc-instance-variable-decl-list: + objc-visibility-spec + objc-instance-variable-decl ; + ; + objc-instance-variable-decl-list objc-visibility-spec + objc-instance-variable-decl-list objc-instance-variable-decl ; + objc-instance-variable-decl-list ; + + objc-visibility-spec: + @private + @protected + @public + + objc-instance-variable-decl: + struct-declaration +*/ + +static void +c_parser_objc_class_instance_variables (c_parser *parser) +{ + gcc_assert (c_parser_next_token_is (parser, CPP_OPEN_BRACE)); + c_parser_consume_token (parser); + while (c_parser_next_token_is_not (parser, CPP_EOF)) + { + tree decls; + /* Parse any stray semicolon. */ + if (c_parser_next_token_is (parser, CPP_SEMICOLON)) + { + pedwarn (c_parser_peek_token (parser)->location, OPT_Wpedantic, + "extra semicolon"); + c_parser_consume_token (parser); + continue; + } + /* Stop if at the end of the instance variables. */ + if (c_parser_next_token_is (parser, CPP_CLOSE_BRACE)) + { + c_parser_consume_token (parser); + break; + } + /* Parse any objc-visibility-spec. */ + if (c_parser_next_token_is_keyword (parser, RID_AT_PRIVATE)) + { + c_parser_consume_token (parser); + objc_set_visibility (OBJC_IVAR_VIS_PRIVATE); + continue; + } + else if (c_parser_next_token_is_keyword (parser, RID_AT_PROTECTED)) + { + c_parser_consume_token (parser); + objc_set_visibility (OBJC_IVAR_VIS_PROTECTED); + continue; + } + else if (c_parser_next_token_is_keyword (parser, RID_AT_PUBLIC)) + { + c_parser_consume_token (parser); + objc_set_visibility (OBJC_IVAR_VIS_PUBLIC); + continue; + } + else if (c_parser_next_token_is_keyword (parser, RID_AT_PACKAGE)) + { + c_parser_consume_token (parser); + objc_set_visibility (OBJC_IVAR_VIS_PACKAGE); + continue; + } + else if (c_parser_next_token_is (parser, CPP_PRAGMA)) + { + c_parser_pragma (parser, pragma_external); + continue; + } + + /* Parse some comma-separated declarations. */ + decls = c_parser_struct_declaration (parser); + if (decls == NULL) + { + /* There is a syntax error. We want to skip the offending + tokens up to the next ';' (included) or '}' + (excluded). */ + + /* First, skip manually a ')' or ']'. This is because they + reduce the nesting level, so c_parser_skip_until_found() + wouldn't be able to skip past them. */ + c_token *token = c_parser_peek_token (parser); + if (token->type == CPP_CLOSE_PAREN || token->type == CPP_CLOSE_SQUARE) + c_parser_consume_token (parser); + + /* Then, do the standard skipping. */ + c_parser_skip_until_found (parser, CPP_SEMICOLON, NULL); + + /* We hopefully recovered. Start normal parsing again. */ + parser->error = false; + continue; + } + else + { + /* Comma-separated instance variables are chained together + in reverse order; add them one by one. */ + tree ivar = nreverse (decls); + for (; ivar; ivar = DECL_CHAIN (ivar)) + objc_add_instance_variable (copy_node (ivar)); + } + c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>"); + } +} + +/* Parse an objc-class-declaration. + + objc-class-declaration: + @class identifier-list ; +*/ + +static void +c_parser_objc_class_declaration (c_parser *parser) +{ + gcc_assert (c_parser_next_token_is_keyword (parser, RID_AT_CLASS)); + c_parser_consume_token (parser); + /* Any identifiers, including those declared as type names, are OK + here. */ + while (true) + { + tree id; + if (c_parser_next_token_is_not (parser, CPP_NAME)) + { + c_parser_error (parser, "expected identifier"); + c_parser_skip_until_found (parser, CPP_SEMICOLON, NULL); + parser->error = false; + return; + } + id = c_parser_peek_token (parser)->value; + objc_declare_class (id); + c_parser_consume_token (parser); + if (c_parser_next_token_is (parser, CPP_COMMA)) + c_parser_consume_token (parser); + else + break; + } + c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>"); +} + +/* Parse an objc-alias-declaration. + + objc-alias-declaration: + @compatibility_alias identifier identifier ; +*/ + +static void +c_parser_objc_alias_declaration (c_parser *parser) +{ + tree id1, id2; + gcc_assert (c_parser_next_token_is_keyword (parser, RID_AT_ALIAS)); + c_parser_consume_token (parser); + if (c_parser_next_token_is_not (parser, CPP_NAME)) + { + c_parser_error (parser, "expected identifier"); + c_parser_skip_until_found (parser, CPP_SEMICOLON, NULL); + return; + } + id1 = c_parser_peek_token (parser)->value; + c_parser_consume_token (parser); + if (c_parser_next_token_is_not (parser, CPP_NAME)) + { + c_parser_error (parser, "expected identifier"); + c_parser_skip_until_found (parser, CPP_SEMICOLON, NULL); + return; + } + id2 = c_parser_peek_token (parser)->value; + c_parser_consume_token (parser); + c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>"); + objc_declare_alias (id1, id2); +} + +/* Parse an objc-protocol-definition. + + objc-protocol-definition: + @protocol identifier objc-protocol-refs[opt] objc-methodprotolist @end + @protocol identifier-list ; + + "@protocol identifier ;" should be resolved as "@protocol + identifier-list ;": objc-methodprotolist may not start with a + semicolon in the first alternative if objc-protocol-refs are + omitted. */ + +static void +c_parser_objc_protocol_definition (c_parser *parser, tree attributes) +{ + gcc_assert (c_parser_next_token_is_keyword (parser, RID_AT_PROTOCOL)); + + c_parser_consume_token (parser); + if (c_parser_next_token_is_not (parser, CPP_NAME)) + { + c_parser_error (parser, "expected identifier"); + return; + } + if (c_parser_peek_2nd_token (parser)->type == CPP_COMMA + || c_parser_peek_2nd_token (parser)->type == CPP_SEMICOLON) + { + /* Any identifiers, including those declared as type names, are + OK here. */ + while (true) + { + tree id; + if (c_parser_next_token_is_not (parser, CPP_NAME)) + { + c_parser_error (parser, "expected identifier"); + break; + } + id = c_parser_peek_token (parser)->value; + objc_declare_protocol (id, attributes); + c_parser_consume_token (parser); + if (c_parser_next_token_is (parser, CPP_COMMA)) + c_parser_consume_token (parser); + else + break; + } + c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>"); + } + else + { + tree id = c_parser_peek_token (parser)->value; + tree proto = NULL_TREE; + c_parser_consume_token (parser); + if (c_parser_next_token_is (parser, CPP_LESS)) + proto = c_parser_objc_protocol_refs (parser); + parser->objc_pq_context = true; + objc_start_protocol (id, proto, attributes); + c_parser_objc_methodprotolist (parser); + c_parser_require_keyword (parser, RID_AT_END, "expected %<@end%>"); + parser->objc_pq_context = false; + objc_finish_interface (); + } +} + +/* Parse an objc-method-type. + + objc-method-type: + + + - + + Return true if it is a class method (+) and false if it is + an instance method (-). +*/ +static inline bool +c_parser_objc_method_type (c_parser *parser) +{ + switch (c_parser_peek_token (parser)->type) + { + case CPP_PLUS: + c_parser_consume_token (parser); + return true; + case CPP_MINUS: + c_parser_consume_token (parser); + return false; + default: + gcc_unreachable (); + } +} + +/* Parse an objc-method-definition. + + objc-method-definition: + objc-method-type objc-method-decl ;[opt] compound-statement +*/ + +static void +c_parser_objc_method_definition (c_parser *parser) +{ + bool is_class_method = c_parser_objc_method_type (parser); + tree decl, attributes = NULL_TREE, expr = NULL_TREE; + parser->objc_pq_context = true; + decl = c_parser_objc_method_decl (parser, is_class_method, &attributes, + &expr); + if (decl == error_mark_node) + return; /* Bail here. */ + + if (c_parser_next_token_is (parser, CPP_SEMICOLON)) + { + c_parser_consume_token (parser); + pedwarn (c_parser_peek_token (parser)->location, OPT_Wpedantic, + "extra semicolon in method definition specified"); + } + + if (!c_parser_next_token_is (parser, CPP_OPEN_BRACE)) + { + c_parser_error (parser, "expected %<{%>"); + return; + } + + parser->objc_pq_context = false; + if (objc_start_method_definition (is_class_method, decl, attributes, expr)) + { + add_stmt (c_parser_compound_statement (parser)); + objc_finish_method_definition (current_function_decl); + } + else + { + /* This code is executed when we find a method definition + outside of an @implementation context (or invalid for other + reasons). Parse the method (to keep going) but do not emit + any code. + */ + c_parser_compound_statement (parser); + } +} + +/* Parse an objc-methodprotolist. + + objc-methodprotolist: + empty + objc-methodprotolist objc-methodproto + objc-methodprotolist declaration + objc-methodprotolist ; + @optional + @required + + The declaration is a data definition, which may be missing + declaration specifiers under the same rules and diagnostics as + other data definitions outside functions, and the stray semicolon + is diagnosed the same way as a stray semicolon outside a + function. */ + +static void +c_parser_objc_methodprotolist (c_parser *parser) +{ + while (true) + { + /* The list is terminated by @end. */ + switch (c_parser_peek_token (parser)->type) + { + case CPP_SEMICOLON: + pedwarn (c_parser_peek_token (parser)->location, OPT_Wpedantic, + "ISO C does not allow extra %<;%> outside of a function"); + c_parser_consume_token (parser); + break; + case CPP_PLUS: + case CPP_MINUS: + c_parser_objc_methodproto (parser); + break; + case CPP_PRAGMA: + c_parser_pragma (parser, pragma_external); + break; + case CPP_EOF: + return; + default: + if (c_parser_next_token_is_keyword (parser, RID_AT_END)) + return; + else if (c_parser_next_token_is_keyword (parser, RID_AT_PROPERTY)) + c_parser_objc_at_property_declaration (parser); + else if (c_parser_next_token_is_keyword (parser, RID_AT_OPTIONAL)) + { + objc_set_method_opt (true); + c_parser_consume_token (parser); + } + else if (c_parser_next_token_is_keyword (parser, RID_AT_REQUIRED)) + { + objc_set_method_opt (false); + c_parser_consume_token (parser); + } + else + c_parser_declaration_or_fndef (parser, false, false, true, + false, true, NULL); + break; + } + } +} + +/* Parse an objc-methodproto. + + objc-methodproto: + objc-method-type objc-method-decl ; +*/ + +static void +c_parser_objc_methodproto (c_parser *parser) +{ + bool is_class_method = c_parser_objc_method_type (parser); + tree decl, attributes = NULL_TREE; + + /* Remember protocol qualifiers in prototypes. */ + parser->objc_pq_context = true; + decl = c_parser_objc_method_decl (parser, is_class_method, &attributes, + NULL); + /* Forget protocol qualifiers now. */ + parser->objc_pq_context = false; + + /* Do not allow the presence of attributes to hide an erroneous + method implementation in the interface section. */ + if (!c_parser_next_token_is (parser, CPP_SEMICOLON)) + { + c_parser_error (parser, "expected %<;%>"); + return; + } + + if (decl != error_mark_node) + objc_add_method_declaration (is_class_method, decl, attributes); + + c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>"); +} + +/* If we are at a position that method attributes may be present, check that + there are not any parsed already (a syntax error) and then collect any + specified at the current location. Finally, if new attributes were present, + check that the next token is legal ( ';' for decls and '{' for defs). */ + +static bool +c_parser_objc_maybe_method_attributes (c_parser* parser, tree* attributes) +{ + bool bad = false; + if (*attributes) + { + c_parser_error (parser, + "method attributes must be specified at the end only"); + *attributes = NULL_TREE; + bad = true; + } + + if (c_parser_next_token_is_keyword (parser, RID_ATTRIBUTE)) + *attributes = c_parser_attributes (parser); + + /* If there were no attributes here, just report any earlier error. */ + if (*attributes == NULL_TREE || bad) + return bad; + + /* If the attributes are followed by a ; or {, then just report any earlier + error. */ + if (c_parser_next_token_is (parser, CPP_SEMICOLON) + || c_parser_next_token_is (parser, CPP_OPEN_BRACE)) + return bad; + + /* We've got attributes, but not at the end. */ + c_parser_error (parser, + "expected %<;%> or %<{%> after method attribute definition"); + return true; +} + +/* Parse an objc-method-decl. + + objc-method-decl: + ( objc-type-name ) objc-selector + objc-selector + ( objc-type-name ) objc-keyword-selector objc-optparmlist + objc-keyword-selector objc-optparmlist + attributes + + objc-keyword-selector: + objc-keyword-decl + objc-keyword-selector objc-keyword-decl + + objc-keyword-decl: + objc-selector : ( objc-type-name ) identifier + objc-selector : identifier + : ( objc-type-name ) identifier + : identifier + + objc-optparmlist: + objc-optparms objc-optellipsis + + objc-optparms: + empty + objc-opt-parms , parameter-declaration + + objc-optellipsis: + empty + , ... +*/ + +static tree +c_parser_objc_method_decl (c_parser *parser, bool is_class_method, + tree *attributes, tree *expr) +{ + tree type = NULL_TREE; + tree sel; + tree parms = NULL_TREE; + bool ellipsis = false; + bool attr_err = false; + + *attributes = NULL_TREE; + if (c_parser_next_token_is (parser, CPP_OPEN_PAREN)) + { + c_parser_consume_token (parser); + type = c_parser_objc_type_name (parser); + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); + } + sel = c_parser_objc_selector (parser); + /* If there is no selector, or a colon follows, we have an + objc-keyword-selector. If there is a selector, and a colon does + not follow, that selector ends the objc-method-decl. */ + if (!sel || c_parser_next_token_is (parser, CPP_COLON)) + { + tree tsel = sel; + tree list = NULL_TREE; + while (true) + { + tree atype = NULL_TREE, id, keyworddecl; + tree param_attr = NULL_TREE; + if (!c_parser_require (parser, CPP_COLON, "expected %<:%>")) + break; + if (c_parser_next_token_is (parser, CPP_OPEN_PAREN)) + { + c_parser_consume_token (parser); + atype = c_parser_objc_type_name (parser); + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, + "expected %<)%>"); + } + /* New ObjC allows attributes on method parameters. */ + if (c_parser_next_token_is_keyword (parser, RID_ATTRIBUTE)) + param_attr = c_parser_attributes (parser); + if (c_parser_next_token_is_not (parser, CPP_NAME)) + { + c_parser_error (parser, "expected identifier"); + return error_mark_node; + } + id = c_parser_peek_token (parser)->value; + c_parser_consume_token (parser); + keyworddecl = objc_build_keyword_decl (tsel, atype, id, param_attr); + list = chainon (list, keyworddecl); + tsel = c_parser_objc_selector (parser); + if (!tsel && c_parser_next_token_is_not (parser, CPP_COLON)) + break; + } + + attr_err |= c_parser_objc_maybe_method_attributes (parser, attributes) ; + + /* Parse the optional parameter list. Optional Objective-C + method parameters follow the C syntax, and may include '...' + to denote a variable number of arguments. */ + parms = make_node (TREE_LIST); + while (c_parser_next_token_is (parser, CPP_COMMA)) + { + struct c_parm *parm; + c_parser_consume_token (parser); + if (c_parser_next_token_is (parser, CPP_ELLIPSIS)) + { + ellipsis = true; + c_parser_consume_token (parser); + attr_err |= c_parser_objc_maybe_method_attributes + (parser, attributes) ; + break; + } + parm = c_parser_parameter_declaration (parser, NULL_TREE); + if (parm == NULL) + break; + parms = chainon (parms, + build_tree_list (NULL_TREE, grokparm (parm, expr))); + } + sel = list; + } + else + attr_err |= c_parser_objc_maybe_method_attributes (parser, attributes) ; + + if (sel == NULL) + { + c_parser_error (parser, "objective-c method declaration is expected"); + return error_mark_node; + } + + if (attr_err) + return error_mark_node; + + return objc_build_method_signature (is_class_method, type, sel, parms, ellipsis); +} + +/* Parse an objc-type-name. + + objc-type-name: + objc-type-qualifiers[opt] type-name + objc-type-qualifiers[opt] + + objc-type-qualifiers: + objc-type-qualifier + objc-type-qualifiers objc-type-qualifier + + objc-type-qualifier: one of + in out inout bycopy byref oneway +*/ + +static tree +c_parser_objc_type_name (c_parser *parser) +{ + tree quals = NULL_TREE; + struct c_type_name *type_name = NULL; + tree type = NULL_TREE; + while (true) + { + c_token *token = c_parser_peek_token (parser); + if (token->type == CPP_KEYWORD + && (token->keyword == RID_IN + || token->keyword == RID_OUT + || token->keyword == RID_INOUT + || token->keyword == RID_BYCOPY + || token->keyword == RID_BYREF + || token->keyword == RID_ONEWAY)) + { + quals = chainon (build_tree_list (NULL_TREE, token->value), quals); + c_parser_consume_token (parser); + } + else + break; + } + if (c_parser_next_tokens_start_typename (parser, cla_prefer_type)) + type_name = c_parser_type_name (parser); + if (type_name) + type = groktypename (type_name, NULL, NULL); + + /* If the type is unknown, and error has already been produced and + we need to recover from the error. In that case, use NULL_TREE + for the type, as if no type had been specified; this will use the + default type ('id') which is good for error recovery. */ + if (type == error_mark_node) + type = NULL_TREE; + + return build_tree_list (quals, type); +} + +/* Parse objc-protocol-refs. + + objc-protocol-refs: + < identifier-list > +*/ + +static tree +c_parser_objc_protocol_refs (c_parser *parser) +{ + tree list = NULL_TREE; + gcc_assert (c_parser_next_token_is (parser, CPP_LESS)); + c_parser_consume_token (parser); + /* Any identifiers, including those declared as type names, are OK + here. */ + while (true) + { + tree id; + if (c_parser_next_token_is_not (parser, CPP_NAME)) + { + c_parser_error (parser, "expected identifier"); + break; + } + id = c_parser_peek_token (parser)->value; + list = chainon (list, build_tree_list (NULL_TREE, id)); + c_parser_consume_token (parser); + if (c_parser_next_token_is (parser, CPP_COMMA)) + c_parser_consume_token (parser); + else + break; + } + c_parser_require (parser, CPP_GREATER, "expected %<>%>"); + return list; +} + +/* Parse an objc-try-catch-finally-statement. + + objc-try-catch-finally-statement: + @try compound-statement objc-catch-list[opt] + @try compound-statement objc-catch-list[opt] @finally compound-statement + + objc-catch-list: + @catch ( objc-catch-parameter-declaration ) compound-statement + objc-catch-list @catch ( objc-catch-parameter-declaration ) compound-statement + + objc-catch-parameter-declaration: + parameter-declaration + '...' + + where '...' is to be interpreted literally, that is, it means CPP_ELLIPSIS. + + PS: This function is identical to cp_parser_objc_try_catch_finally_statement + for C++. Keep them in sync. */ + +static void +c_parser_objc_try_catch_finally_statement (c_parser *parser) +{ + location_t location; + tree stmt; + + gcc_assert (c_parser_next_token_is_keyword (parser, RID_AT_TRY)); + c_parser_consume_token (parser); + location = c_parser_peek_token (parser)->location; + objc_maybe_warn_exceptions (location); + stmt = c_parser_compound_statement (parser); + objc_begin_try_stmt (location, stmt); + + while (c_parser_next_token_is_keyword (parser, RID_AT_CATCH)) + { + struct c_parm *parm; + tree parameter_declaration = error_mark_node; + bool seen_open_paren = false; + + c_parser_consume_token (parser); + if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) + seen_open_paren = true; + if (c_parser_next_token_is (parser, CPP_ELLIPSIS)) + { + /* We have "@catch (...)" (where the '...' are literally + what is in the code). Skip the '...'. + parameter_declaration is set to NULL_TREE, and + objc_being_catch_clauses() knows that that means + '...'. */ + c_parser_consume_token (parser); + parameter_declaration = NULL_TREE; + } + else + { + /* We have "@catch (NSException *exception)" or something + like that. Parse the parameter declaration. */ + parm = c_parser_parameter_declaration (parser, NULL_TREE); + if (parm == NULL) + parameter_declaration = error_mark_node; + else + parameter_declaration = grokparm (parm, NULL); + } + if (seen_open_paren) + c_parser_require (parser, CPP_CLOSE_PAREN, "expected %<)%>"); + else + { + /* If there was no open parenthesis, we are recovering from + an error, and we are trying to figure out what mistake + the user has made. */ + + /* If there is an immediate closing parenthesis, the user + probably forgot the opening one (ie, they typed "@catch + NSException *e)". Parse the closing parenthesis and keep + going. */ + if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN)) + c_parser_consume_token (parser); + + /* If these is no immediate closing parenthesis, the user + probably doesn't know that parenthesis are required at + all (ie, they typed "@catch NSException *e"). So, just + forget about the closing parenthesis and keep going. */ + } + objc_begin_catch_clause (parameter_declaration); + if (c_parser_require (parser, CPP_OPEN_BRACE, "expected %<{%>")) + c_parser_compound_statement_nostart (parser); + objc_finish_catch_clause (); + } + if (c_parser_next_token_is_keyword (parser, RID_AT_FINALLY)) + { + c_parser_consume_token (parser); + location = c_parser_peek_token (parser)->location; + stmt = c_parser_compound_statement (parser); + objc_build_finally_clause (location, stmt); + } + objc_finish_try_stmt (); +} + +/* Parse an objc-synchronized-statement. + + objc-synchronized-statement: + @synchronized ( expression ) compound-statement +*/ + +static void +c_parser_objc_synchronized_statement (c_parser *parser) +{ + location_t loc; + tree expr, stmt; + gcc_assert (c_parser_next_token_is_keyword (parser, RID_AT_SYNCHRONIZED)); + c_parser_consume_token (parser); + loc = c_parser_peek_token (parser)->location; + objc_maybe_warn_exceptions (loc); + if (c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) + { + expr = c_parser_expression (parser).value; + expr = c_fully_fold (expr, false, NULL); + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); + } + else + expr = error_mark_node; + stmt = c_parser_compound_statement (parser); + objc_build_synchronized (loc, expr, stmt); +} + +/* Parse an objc-selector; return NULL_TREE without an error if the + next token is not an objc-selector. + + objc-selector: + identifier + one of + enum struct union if else while do for switch case default + break continue return goto asm sizeof typeof __alignof + unsigned long const short volatile signed restrict _Complex + in out inout bycopy byref oneway int char float double void _Bool + + ??? Why this selection of keywords but not, for example, storage + class specifiers? */ + +static tree +c_parser_objc_selector (c_parser *parser) +{ + c_token *token = c_parser_peek_token (parser); + tree value = token->value; + if (token->type == CPP_NAME) + { + c_parser_consume_token (parser); + return value; + } + if (token->type != CPP_KEYWORD) + return NULL_TREE; + switch (token->keyword) + { + case RID_ENUM: + case RID_STRUCT: + case RID_UNION: + case RID_IF: + case RID_ELSE: + case RID_WHILE: + case RID_DO: + case RID_FOR: + case RID_SWITCH: + case RID_CASE: + case RID_DEFAULT: + case RID_BREAK: + case RID_CONTINUE: + case RID_RETURN: + case RID_GOTO: + case RID_ASM: + case RID_SIZEOF: + case RID_TYPEOF: + case RID_ALIGNOF: + case RID_UNSIGNED: + case RID_LONG: + case RID_INT128: + case RID_CONST: + case RID_SHORT: + case RID_VOLATILE: + case RID_SIGNED: + case RID_RESTRICT: + case RID_COMPLEX: + case RID_IN: + case RID_OUT: + case RID_INOUT: + case RID_BYCOPY: + case RID_BYREF: + case RID_ONEWAY: + case RID_INT: + case RID_CHAR: + case RID_FLOAT: + case RID_DOUBLE: + case RID_VOID: + case RID_BOOL: + c_parser_consume_token (parser); + return value; + default: + return NULL_TREE; + } +} + +/* Parse an objc-selector-arg. + + objc-selector-arg: + objc-selector + objc-keywordname-list + + objc-keywordname-list: + objc-keywordname + objc-keywordname-list objc-keywordname + + objc-keywordname: + objc-selector : + : +*/ + +static tree +c_parser_objc_selector_arg (c_parser *parser) +{ + tree sel = c_parser_objc_selector (parser); + tree list = NULL_TREE; + if (sel && c_parser_next_token_is_not (parser, CPP_COLON)) + return sel; + while (true) + { + if (!c_parser_require (parser, CPP_COLON, "expected %<:%>")) + return list; + list = chainon (list, build_tree_list (sel, NULL_TREE)); + sel = c_parser_objc_selector (parser); + if (!sel && c_parser_next_token_is_not (parser, CPP_COLON)) + break; + } + return list; +} + +/* Parse an objc-receiver. + + objc-receiver: + expression + class-name + type-name +*/ + +static tree +c_parser_objc_receiver (c_parser *parser) +{ + if (c_parser_peek_token (parser)->type == CPP_NAME + && (c_parser_peek_token (parser)->id_kind == C_ID_TYPENAME + || c_parser_peek_token (parser)->id_kind == C_ID_CLASSNAME)) + { + tree id = c_parser_peek_token (parser)->value; + c_parser_consume_token (parser); + return objc_get_class_reference (id); + } + return c_fully_fold (c_parser_expression (parser).value, false, NULL); +} + +/* Parse objc-message-args. + + objc-message-args: + objc-selector + objc-keywordarg-list + + objc-keywordarg-list: + objc-keywordarg + objc-keywordarg-list objc-keywordarg + + objc-keywordarg: + objc-selector : objc-keywordexpr + : objc-keywordexpr +*/ + +static tree +c_parser_objc_message_args (c_parser *parser) +{ + tree sel = c_parser_objc_selector (parser); + tree list = NULL_TREE; + if (sel && c_parser_next_token_is_not (parser, CPP_COLON)) + return sel; + while (true) + { + tree keywordexpr; + if (!c_parser_require (parser, CPP_COLON, "expected %<:%>")) + return error_mark_node; + keywordexpr = c_parser_objc_keywordexpr (parser); + list = chainon (list, build_tree_list (sel, keywordexpr)); + sel = c_parser_objc_selector (parser); + if (!sel && c_parser_next_token_is_not (parser, CPP_COLON)) + break; + } + return list; +} + +/* Parse an objc-keywordexpr. + + objc-keywordexpr: + nonempty-expr-list +*/ + +static tree +c_parser_objc_keywordexpr (c_parser *parser) +{ + tree ret; + VEC(tree,gc) *expr_list = c_parser_expr_list (parser, true, true, NULL); + if (VEC_length (tree, expr_list) == 1) + { + /* Just return the expression, remove a level of + indirection. */ + ret = VEC_index (tree, expr_list, 0); + } + else + { + /* We have a comma expression, we will collapse later. */ + ret = build_tree_list_vec (expr_list); + } + release_tree_vector (expr_list); + return ret; +} + +/* A check, needed in several places, that ObjC interface, implementation or + method definitions are not prefixed by incorrect items. */ +static bool +c_parser_objc_diagnose_bad_element_prefix (c_parser *parser, + struct c_declspecs *specs) +{ + if (!specs->declspecs_seen_p || specs->non_sc_seen_p + || specs->typespec_kind != ctsk_none) + { + c_parser_error (parser, + "no type or storage class may be specified here,"); + c_parser_skip_to_end_of_block_or_statement (parser); + return true; + } + return false; +} + +/* Parse an Objective-C @property declaration. The syntax is: + + objc-property-declaration: + '@property' objc-property-attributes[opt] struct-declaration ; + + objc-property-attributes: + '(' objc-property-attribute-list ')' + + objc-property-attribute-list: + objc-property-attribute + objc-property-attribute-list, objc-property-attribute + + objc-property-attribute + 'getter' = identifier + 'setter' = identifier + 'readonly' + 'readwrite' + 'assign' + 'retain' + 'copy' + 'nonatomic' + + For example: + @property NSString *name; + @property (readonly) id object; + @property (retain, nonatomic, getter=getTheName) id name; + @property int a, b, c; + + PS: This function is identical to cp_parser_objc_at_propery_declaration + for C++. Keep them in sync. */ +static void +c_parser_objc_at_property_declaration (c_parser *parser) +{ + /* The following variables hold the attributes of the properties as + parsed. They are 'false' or 'NULL_TREE' if the attribute was not + seen. When we see an attribute, we set them to 'true' (if they + are boolean properties) or to the identifier (if they have an + argument, ie, for getter and setter). Note that here we only + parse the list of attributes, check the syntax and accumulate the + attributes that we find. objc_add_property_declaration() will + then process the information. */ + bool property_assign = false; + bool property_copy = false; + tree property_getter_ident = NULL_TREE; + bool property_nonatomic = false; + bool property_readonly = false; + bool property_readwrite = false; + bool property_retain = false; + tree property_setter_ident = NULL_TREE; + + /* 'properties' is the list of properties that we read. Usually a + single one, but maybe more (eg, in "@property int a, b, c;" there + are three). */ + tree properties; + location_t loc; + + loc = c_parser_peek_token (parser)->location; + gcc_assert (c_parser_next_token_is_keyword (parser, RID_AT_PROPERTY)); + + c_parser_consume_token (parser); /* Eat '@property'. */ + + /* Parse the optional attribute list... */ + if (c_parser_next_token_is (parser, CPP_OPEN_PAREN)) + { + /* Eat the '(' */ + c_parser_consume_token (parser); + + /* Property attribute keywords are valid now. */ + parser->objc_property_attr_context = true; + + while (true) + { + bool syntax_error = false; + c_token *token = c_parser_peek_token (parser); + enum rid keyword; + + if (token->type != CPP_KEYWORD) + { + if (token->type == CPP_CLOSE_PAREN) + c_parser_error (parser, "expected identifier"); + else + { + c_parser_consume_token (parser); + c_parser_error (parser, "unknown property attribute"); + } + break; + } + keyword = token->keyword; + c_parser_consume_token (parser); + switch (keyword) + { + case RID_ASSIGN: property_assign = true; break; + case RID_COPY: property_copy = true; break; + case RID_NONATOMIC: property_nonatomic = true; break; + case RID_READONLY: property_readonly = true; break; + case RID_READWRITE: property_readwrite = true; break; + case RID_RETAIN: property_retain = true; break; + + case RID_GETTER: + case RID_SETTER: + if (c_parser_next_token_is_not (parser, CPP_EQ)) + { + if (keyword == RID_GETTER) + c_parser_error (parser, + "missing %<=%> (after %<getter%> attribute)"); + else + c_parser_error (parser, + "missing %<=%> (after %<setter%> attribute)"); + syntax_error = true; + break; + } + c_parser_consume_token (parser); /* eat the = */ + if (c_parser_next_token_is_not (parser, CPP_NAME)) + { + c_parser_error (parser, "expected identifier"); + syntax_error = true; + break; + } + if (keyword == RID_SETTER) + { + if (property_setter_ident != NULL_TREE) + c_parser_error (parser, "the %<setter%> attribute may only be specified once"); + else + property_setter_ident = c_parser_peek_token (parser)->value; + c_parser_consume_token (parser); + if (c_parser_next_token_is_not (parser, CPP_COLON)) + c_parser_error (parser, "setter name must terminate with %<:%>"); + else + c_parser_consume_token (parser); + } + else + { + if (property_getter_ident != NULL_TREE) + c_parser_error (parser, "the %<getter%> attribute may only be specified once"); + else + property_getter_ident = c_parser_peek_token (parser)->value; + c_parser_consume_token (parser); + } + break; + default: + c_parser_error (parser, "unknown property attribute"); + syntax_error = true; + break; + } + + if (syntax_error) + break; + + if (c_parser_next_token_is (parser, CPP_COMMA)) + c_parser_consume_token (parser); + else + break; + } + parser->objc_property_attr_context = false; + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); + } + /* ... and the property declaration(s). */ + properties = c_parser_struct_declaration (parser); + + if (properties == error_mark_node) + { + c_parser_skip_until_found (parser, CPP_SEMICOLON, NULL); + parser->error = false; + return; + } + + if (properties == NULL_TREE) + c_parser_error (parser, "expected identifier"); + else + { + /* Comma-separated properties are chained together in + reverse order; add them one by one. */ + properties = nreverse (properties); + + for (; properties; properties = TREE_CHAIN (properties)) + objc_add_property_declaration (loc, copy_node (properties), + property_readonly, property_readwrite, + property_assign, property_retain, + property_copy, property_nonatomic, + property_getter_ident, property_setter_ident); + } + + c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>"); + parser->error = false; +} + +/* Parse an Objective-C @synthesize declaration. The syntax is: + + objc-synthesize-declaration: + @synthesize objc-synthesize-identifier-list ; + + objc-synthesize-identifier-list: + objc-synthesize-identifier + objc-synthesize-identifier-list, objc-synthesize-identifier + + objc-synthesize-identifier + identifier + identifier = identifier + + For example: + @synthesize MyProperty; + @synthesize OneProperty, AnotherProperty=MyIvar, YetAnotherProperty; + + PS: This function is identical to cp_parser_objc_at_synthesize_declaration + for C++. Keep them in sync. +*/ +static void +c_parser_objc_at_synthesize_declaration (c_parser *parser) +{ + tree list = NULL_TREE; + location_t loc; + gcc_assert (c_parser_next_token_is_keyword (parser, RID_AT_SYNTHESIZE)); + loc = c_parser_peek_token (parser)->location; + + c_parser_consume_token (parser); + while (true) + { + tree property, ivar; + if (c_parser_next_token_is_not (parser, CPP_NAME)) + { + c_parser_error (parser, "expected identifier"); + c_parser_skip_until_found (parser, CPP_SEMICOLON, NULL); + /* Once we find the semicolon, we can resume normal parsing. + We have to reset parser->error manually because + c_parser_skip_until_found() won't reset it for us if the + next token is precisely a semicolon. */ + parser->error = false; + return; + } + property = c_parser_peek_token (parser)->value; + c_parser_consume_token (parser); + if (c_parser_next_token_is (parser, CPP_EQ)) + { + c_parser_consume_token (parser); + if (c_parser_next_token_is_not (parser, CPP_NAME)) + { + c_parser_error (parser, "expected identifier"); + c_parser_skip_until_found (parser, CPP_SEMICOLON, NULL); + parser->error = false; + return; + } + ivar = c_parser_peek_token (parser)->value; + c_parser_consume_token (parser); + } + else + ivar = NULL_TREE; + list = chainon (list, build_tree_list (ivar, property)); + if (c_parser_next_token_is (parser, CPP_COMMA)) + c_parser_consume_token (parser); + else + break; + } + c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>"); + objc_add_synthesize_declaration (loc, list); +} + +/* Parse an Objective-C @dynamic declaration. The syntax is: + + objc-dynamic-declaration: + @dynamic identifier-list ; + + For example: + @dynamic MyProperty; + @dynamic MyProperty, AnotherProperty; + + PS: This function is identical to cp_parser_objc_at_dynamic_declaration + for C++. Keep them in sync. +*/ +static void +c_parser_objc_at_dynamic_declaration (c_parser *parser) +{ + tree list = NULL_TREE; + location_t loc; + gcc_assert (c_parser_next_token_is_keyword (parser, RID_AT_DYNAMIC)); + loc = c_parser_peek_token (parser)->location; + + c_parser_consume_token (parser); + while (true) + { + tree property; + if (c_parser_next_token_is_not (parser, CPP_NAME)) + { + c_parser_error (parser, "expected identifier"); + c_parser_skip_until_found (parser, CPP_SEMICOLON, NULL); + parser->error = false; + return; + } + property = c_parser_peek_token (parser)->value; + list = chainon (list, build_tree_list (NULL_TREE, property)); + c_parser_consume_token (parser); + if (c_parser_next_token_is (parser, CPP_COMMA)) + c_parser_consume_token (parser); + else + break; + } + c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>"); + objc_add_dynamic_declaration (loc, list); +} + + +/* Handle pragmas. Some OpenMP pragmas are associated with, and therefore + should be considered, statements. ALLOW_STMT is true if we're within + the context of a function and such pragmas are to be allowed. Returns + true if we actually parsed such a pragma. */ + +static bool +c_parser_pragma (c_parser *parser, enum pragma_context context) +{ + unsigned int id; + + id = c_parser_peek_token (parser)->pragma_kind; + gcc_assert (id != PRAGMA_NONE); + + switch (id) + { + case PRAGMA_OMP_BARRIER: + if (context != pragma_compound) + { + if (context == pragma_stmt) + c_parser_error (parser, "%<#pragma omp barrier%> may only be " + "used in compound statements"); + goto bad_stmt; + } + c_parser_omp_barrier (parser); + return false; + + case PRAGMA_OMP_FLUSH: + if (context != pragma_compound) + { + if (context == pragma_stmt) + c_parser_error (parser, "%<#pragma omp flush%> may only be " + "used in compound statements"); + goto bad_stmt; + } + c_parser_omp_flush (parser); + return false; + + case PRAGMA_OMP_TASKWAIT: + if (context != pragma_compound) + { + if (context == pragma_stmt) + c_parser_error (parser, "%<#pragma omp taskwait%> may only be " + "used in compound statements"); + goto bad_stmt; + } + c_parser_omp_taskwait (parser); + return false; + + case PRAGMA_OMP_TASKYIELD: + if (context != pragma_compound) + { + if (context == pragma_stmt) + c_parser_error (parser, "%<#pragma omp taskyield%> may only be " + "used in compound statements"); + goto bad_stmt; + } + c_parser_omp_taskyield (parser); + return false; + + case PRAGMA_OMP_THREADPRIVATE: + c_parser_omp_threadprivate (parser); + return false; + + case PRAGMA_OMP_SECTION: + error_at (c_parser_peek_token (parser)->location, + "%<#pragma omp section%> may only be used in " + "%<#pragma omp sections%> construct"); + c_parser_skip_until_found (parser, CPP_PRAGMA_EOL, NULL); + return false; + + case PRAGMA_GCC_PCH_PREPROCESS: + c_parser_error (parser, "%<#pragma GCC pch_preprocess%> must be first"); + c_parser_skip_until_found (parser, CPP_PRAGMA_EOL, NULL); + return false; + + default: + if (id < PRAGMA_FIRST_EXTERNAL) + { + if (context == pragma_external) + { + bad_stmt: + c_parser_error (parser, "expected declaration specifiers"); + c_parser_skip_until_found (parser, CPP_PRAGMA_EOL, NULL); + return false; + } + c_parser_omp_construct (parser); + return true; + } + break; + } + + c_parser_consume_pragma (parser); + c_invoke_pragma_handler (id); + + /* Skip to EOL, but suppress any error message. Those will have been + generated by the handler routine through calling error, as opposed + to calling c_parser_error. */ + parser->error = true; + c_parser_skip_to_pragma_eol (parser); + + return false; +} + +/* The interface the pragma parsers have to the lexer. */ + +enum cpp_ttype +pragma_lex (tree *value) +{ + c_token *tok = c_parser_peek_token (the_parser); + enum cpp_ttype ret = tok->type; + + *value = tok->value; + if (ret == CPP_PRAGMA_EOL || ret == CPP_EOF) + ret = CPP_EOF; + else + { + if (ret == CPP_KEYWORD) + ret = CPP_NAME; + c_parser_consume_token (the_parser); + } + + return ret; +} + +static void +c_parser_pragma_pch_preprocess (c_parser *parser) +{ + tree name = NULL; + + c_parser_consume_pragma (parser); + if (c_parser_next_token_is (parser, CPP_STRING)) + { + name = c_parser_peek_token (parser)->value; + c_parser_consume_token (parser); + } + else + c_parser_error (parser, "expected string literal"); + c_parser_skip_to_pragma_eol (parser); + + if (name) + c_common_pch_pragma (parse_in, TREE_STRING_POINTER (name)); +} + +/* OpenMP 2.5 parsing routines. */ + +/* Returns name of the next clause. + If the clause is not recognized PRAGMA_OMP_CLAUSE_NONE is returned and + the token is not consumed. Otherwise appropriate pragma_omp_clause is + returned and the token is consumed. */ + +static pragma_omp_clause +c_parser_omp_clause_name (c_parser *parser) +{ + pragma_omp_clause result = PRAGMA_OMP_CLAUSE_NONE; + + if (c_parser_next_token_is_keyword (parser, RID_IF)) + result = PRAGMA_OMP_CLAUSE_IF; + else if (c_parser_next_token_is_keyword (parser, RID_DEFAULT)) + result = PRAGMA_OMP_CLAUSE_DEFAULT; + else if (c_parser_next_token_is (parser, CPP_NAME)) + { + const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); + + switch (p[0]) + { + case 'c': + if (!strcmp ("collapse", p)) + result = PRAGMA_OMP_CLAUSE_COLLAPSE; + else if (!strcmp ("copyin", p)) + result = PRAGMA_OMP_CLAUSE_COPYIN; + else if (!strcmp ("copyprivate", p)) + result = PRAGMA_OMP_CLAUSE_COPYPRIVATE; + break; + case 'f': + if (!strcmp ("final", p)) + result = PRAGMA_OMP_CLAUSE_FINAL; + else if (!strcmp ("firstprivate", p)) + result = PRAGMA_OMP_CLAUSE_FIRSTPRIVATE; + break; + case 'l': + if (!strcmp ("lastprivate", p)) + result = PRAGMA_OMP_CLAUSE_LASTPRIVATE; + break; + case 'm': + if (!strcmp ("mergeable", p)) + result = PRAGMA_OMP_CLAUSE_MERGEABLE; + break; + case 'n': + if (!strcmp ("nowait", p)) + result = PRAGMA_OMP_CLAUSE_NOWAIT; + else if (!strcmp ("num_threads", p)) + result = PRAGMA_OMP_CLAUSE_NUM_THREADS; + break; + case 'o': + if (!strcmp ("ordered", p)) + result = PRAGMA_OMP_CLAUSE_ORDERED; + break; + case 'p': + if (!strcmp ("private", p)) + result = PRAGMA_OMP_CLAUSE_PRIVATE; + break; + case 'r': + if (!strcmp ("reduction", p)) + result = PRAGMA_OMP_CLAUSE_REDUCTION; + break; + case 's': + if (!strcmp ("schedule", p)) + result = PRAGMA_OMP_CLAUSE_SCHEDULE; + else if (!strcmp ("shared", p)) + result = PRAGMA_OMP_CLAUSE_SHARED; + break; + case 'u': + if (!strcmp ("untied", p)) + result = PRAGMA_OMP_CLAUSE_UNTIED; + break; + } + } + + if (result != PRAGMA_OMP_CLAUSE_NONE) + c_parser_consume_token (parser); + + return result; +} + +/* Validate that a clause of the given type does not already exist. */ + +static void +check_no_duplicate_clause (tree clauses, enum omp_clause_code code, + const char *name) +{ + tree c; + + for (c = clauses; c ; c = OMP_CLAUSE_CHAIN (c)) + if (OMP_CLAUSE_CODE (c) == code) + { + location_t loc = OMP_CLAUSE_LOCATION (c); + error_at (loc, "too many %qs clauses", name); + break; + } +} + +/* OpenMP 2.5: + variable-list: + identifier + variable-list , identifier + + If KIND is nonzero, create the appropriate node and install the + decl in OMP_CLAUSE_DECL and add the node to the head of the list. + If KIND is nonzero, CLAUSE_LOC is the location of the clause. + + If KIND is zero, create a TREE_LIST with the decl in TREE_PURPOSE; + return the list created. */ + +static tree +c_parser_omp_variable_list (c_parser *parser, + location_t clause_loc, + enum omp_clause_code kind, + tree list) +{ + if (c_parser_next_token_is_not (parser, CPP_NAME) + || c_parser_peek_token (parser)->id_kind != C_ID_ID) + c_parser_error (parser, "expected identifier"); + + while (c_parser_next_token_is (parser, CPP_NAME) + && c_parser_peek_token (parser)->id_kind == C_ID_ID) + { + tree t = lookup_name (c_parser_peek_token (parser)->value); + + if (t == NULL_TREE) + undeclared_variable (c_parser_peek_token (parser)->location, + c_parser_peek_token (parser)->value); + else if (t == error_mark_node) + ; + else if (kind != 0) + { + tree u = build_omp_clause (clause_loc, kind); + OMP_CLAUSE_DECL (u) = t; + OMP_CLAUSE_CHAIN (u) = list; + list = u; + } + else + list = tree_cons (t, NULL_TREE, list); + + c_parser_consume_token (parser); + + if (c_parser_next_token_is_not (parser, CPP_COMMA)) + break; + + c_parser_consume_token (parser); + } + + return list; +} + +/* Similarly, but expect leading and trailing parenthesis. This is a very + common case for omp clauses. */ + +static tree +c_parser_omp_var_list_parens (c_parser *parser, enum omp_clause_code kind, + tree list) +{ + /* The clauses location. */ + location_t loc = c_parser_peek_token (parser)->location; + + if (c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) + { + list = c_parser_omp_variable_list (parser, loc, kind, list); + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); + } + return list; +} + +/* OpenMP 3.0: + collapse ( constant-expression ) */ + +static tree +c_parser_omp_clause_collapse (c_parser *parser, tree list) +{ + tree c, num = error_mark_node; + HOST_WIDE_INT n; + location_t loc; + + check_no_duplicate_clause (list, OMP_CLAUSE_COLLAPSE, "collapse"); + + loc = c_parser_peek_token (parser)->location; + if (c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) + { + num = c_parser_expr_no_commas (parser, NULL).value; + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); + } + if (num == error_mark_node) + return list; + if (!INTEGRAL_TYPE_P (TREE_TYPE (num)) + || !host_integerp (num, 0) + || (n = tree_low_cst (num, 0)) <= 0 + || (int) n != n) + { + error_at (loc, + "collapse argument needs positive constant integer expression"); + return list; + } + c = build_omp_clause (loc, OMP_CLAUSE_COLLAPSE); + OMP_CLAUSE_COLLAPSE_EXPR (c) = num; + OMP_CLAUSE_CHAIN (c) = list; + return c; +} + +/* OpenMP 2.5: + copyin ( variable-list ) */ + +static tree +c_parser_omp_clause_copyin (c_parser *parser, tree list) +{ + return c_parser_omp_var_list_parens (parser, OMP_CLAUSE_COPYIN, list); +} + +/* OpenMP 2.5: + copyprivate ( variable-list ) */ + +static tree +c_parser_omp_clause_copyprivate (c_parser *parser, tree list) +{ + return c_parser_omp_var_list_parens (parser, OMP_CLAUSE_COPYPRIVATE, list); +} + +/* OpenMP 2.5: + default ( shared | none ) */ + +static tree +c_parser_omp_clause_default (c_parser *parser, tree list) +{ + enum omp_clause_default_kind kind = OMP_CLAUSE_DEFAULT_UNSPECIFIED; + location_t loc = c_parser_peek_token (parser)->location; + tree c; + + if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) + return list; + if (c_parser_next_token_is (parser, CPP_NAME)) + { + const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); + + switch (p[0]) + { + case 'n': + if (strcmp ("none", p) != 0) + goto invalid_kind; + kind = OMP_CLAUSE_DEFAULT_NONE; + break; + + case 's': + if (strcmp ("shared", p) != 0) + goto invalid_kind; + kind = OMP_CLAUSE_DEFAULT_SHARED; + break; + + default: + goto invalid_kind; + } + + c_parser_consume_token (parser); + } + else + { + invalid_kind: + c_parser_error (parser, "expected %<none%> or %<shared%>"); + } + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); + + if (kind == OMP_CLAUSE_DEFAULT_UNSPECIFIED) + return list; + + check_no_duplicate_clause (list, OMP_CLAUSE_DEFAULT, "default"); + c = build_omp_clause (loc, OMP_CLAUSE_DEFAULT); + OMP_CLAUSE_CHAIN (c) = list; + OMP_CLAUSE_DEFAULT_KIND (c) = kind; + + return c; +} + +/* OpenMP 2.5: + firstprivate ( variable-list ) */ + +static tree +c_parser_omp_clause_firstprivate (c_parser *parser, tree list) +{ + return c_parser_omp_var_list_parens (parser, OMP_CLAUSE_FIRSTPRIVATE, list); +} + +/* OpenMP 3.1: + final ( expression ) */ + +static tree +c_parser_omp_clause_final (c_parser *parser, tree list) +{ + location_t loc = c_parser_peek_token (parser)->location; + if (c_parser_next_token_is (parser, CPP_OPEN_PAREN)) + { + tree t = c_parser_paren_condition (parser); + tree c; + + check_no_duplicate_clause (list, OMP_CLAUSE_FINAL, "final"); + + c = build_omp_clause (loc, OMP_CLAUSE_FINAL); + OMP_CLAUSE_FINAL_EXPR (c) = t; + OMP_CLAUSE_CHAIN (c) = list; + list = c; + } + else + c_parser_error (parser, "expected %<(%>"); + + return list; +} + +/* OpenMP 2.5: + if ( expression ) */ + +static tree +c_parser_omp_clause_if (c_parser *parser, tree list) +{ + location_t loc = c_parser_peek_token (parser)->location; + if (c_parser_next_token_is (parser, CPP_OPEN_PAREN)) + { + tree t = c_parser_paren_condition (parser); + tree c; + + check_no_duplicate_clause (list, OMP_CLAUSE_IF, "if"); + + c = build_omp_clause (loc, OMP_CLAUSE_IF); + OMP_CLAUSE_IF_EXPR (c) = t; + OMP_CLAUSE_CHAIN (c) = list; + list = c; + } + else + c_parser_error (parser, "expected %<(%>"); + + return list; +} + +/* OpenMP 2.5: + lastprivate ( variable-list ) */ + +static tree +c_parser_omp_clause_lastprivate (c_parser *parser, tree list) +{ + return c_parser_omp_var_list_parens (parser, OMP_CLAUSE_LASTPRIVATE, list); +} + +/* OpenMP 3.1: + mergeable */ + +static tree +c_parser_omp_clause_mergeable (c_parser *parser ATTRIBUTE_UNUSED, tree list) +{ + tree c; + + /* FIXME: Should we allow duplicates? */ + check_no_duplicate_clause (list, OMP_CLAUSE_MERGEABLE, "mergeable"); + + c = build_omp_clause (c_parser_peek_token (parser)->location, + OMP_CLAUSE_MERGEABLE); + OMP_CLAUSE_CHAIN (c) = list; + + return c; +} + +/* OpenMP 2.5: + nowait */ + +static tree +c_parser_omp_clause_nowait (c_parser *parser ATTRIBUTE_UNUSED, tree list) +{ + tree c; + location_t loc = c_parser_peek_token (parser)->location; + + check_no_duplicate_clause (list, OMP_CLAUSE_NOWAIT, "nowait"); + + c = build_omp_clause (loc, OMP_CLAUSE_NOWAIT); + OMP_CLAUSE_CHAIN (c) = list; + return c; +} + +/* OpenMP 2.5: + num_threads ( expression ) */ + +static tree +c_parser_omp_clause_num_threads (c_parser *parser, tree list) +{ + location_t num_threads_loc = c_parser_peek_token (parser)->location; + if (c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) + { + location_t expr_loc = c_parser_peek_token (parser)->location; + tree c, t = c_parser_expression (parser).value; + mark_exp_read (t); + t = c_fully_fold (t, false, NULL); + + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); + + if (!INTEGRAL_TYPE_P (TREE_TYPE (t))) + { + c_parser_error (parser, "expected integer expression"); + return list; + } + + /* Attempt to statically determine when the number isn't positive. */ + c = fold_build2_loc (expr_loc, LE_EXPR, boolean_type_node, t, + build_int_cst (TREE_TYPE (t), 0)); + if (CAN_HAVE_LOCATION_P (c)) + SET_EXPR_LOCATION (c, expr_loc); + if (c == boolean_true_node) + { + warning_at (expr_loc, 0, + "%<num_threads%> value must be positive"); + t = integer_one_node; + } + + check_no_duplicate_clause (list, OMP_CLAUSE_NUM_THREADS, "num_threads"); + + c = build_omp_clause (num_threads_loc, OMP_CLAUSE_NUM_THREADS); + OMP_CLAUSE_NUM_THREADS_EXPR (c) = t; + OMP_CLAUSE_CHAIN (c) = list; + list = c; + } + + return list; +} + +/* OpenMP 2.5: + ordered */ + +static tree +c_parser_omp_clause_ordered (c_parser *parser, tree list) +{ + tree c; + + check_no_duplicate_clause (list, OMP_CLAUSE_ORDERED, "ordered"); + + c = build_omp_clause (c_parser_peek_token (parser)->location, + OMP_CLAUSE_ORDERED); + OMP_CLAUSE_CHAIN (c) = list; + + return c; +} + +/* OpenMP 2.5: + private ( variable-list ) */ + +static tree +c_parser_omp_clause_private (c_parser *parser, tree list) +{ + return c_parser_omp_var_list_parens (parser, OMP_CLAUSE_PRIVATE, list); +} + +/* OpenMP 2.5: + reduction ( reduction-operator : variable-list ) + + reduction-operator: + One of: + * - & ^ | && || + + OpenMP 3.1: + + reduction-operator: + One of: + * - & ^ | && || max min */ + +static tree +c_parser_omp_clause_reduction (c_parser *parser, tree list) +{ + location_t clause_loc = c_parser_peek_token (parser)->location; + if (c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) + { + enum tree_code code; + + switch (c_parser_peek_token (parser)->type) + { + case CPP_PLUS: + code = PLUS_EXPR; + break; + case CPP_MULT: + code = MULT_EXPR; + break; + case CPP_MINUS: + code = MINUS_EXPR; + break; + case CPP_AND: + code = BIT_AND_EXPR; + break; + case CPP_XOR: + code = BIT_XOR_EXPR; + break; + case CPP_OR: + code = BIT_IOR_EXPR; + break; + case CPP_AND_AND: + code = TRUTH_ANDIF_EXPR; + break; + case CPP_OR_OR: + code = TRUTH_ORIF_EXPR; + break; + case CPP_NAME: + { + const char *p + = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); + if (strcmp (p, "min") == 0) + { + code = MIN_EXPR; + break; + } + if (strcmp (p, "max") == 0) + { + code = MAX_EXPR; + break; + } + } + /* FALLTHRU */ + default: + c_parser_error (parser, + "expected %<+%>, %<*%>, %<-%>, %<&%>, " + "%<^%>, %<|%>, %<&&%>, %<||%>, %<min%> or %<max%>"); + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, 0); + return list; + } + c_parser_consume_token (parser); + if (c_parser_require (parser, CPP_COLON, "expected %<:%>")) + { + tree nl, c; + + nl = c_parser_omp_variable_list (parser, clause_loc, + OMP_CLAUSE_REDUCTION, list); + for (c = nl; c != list; c = OMP_CLAUSE_CHAIN (c)) + OMP_CLAUSE_REDUCTION_CODE (c) = code; + + list = nl; + } + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); + } + return list; +} + +/* OpenMP 2.5: + schedule ( schedule-kind ) + schedule ( schedule-kind , expression ) + + schedule-kind: + static | dynamic | guided | runtime | auto +*/ + +static tree +c_parser_omp_clause_schedule (c_parser *parser, tree list) +{ + tree c, t; + location_t loc = c_parser_peek_token (parser)->location; + + if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) + return list; + + c = build_omp_clause (loc, OMP_CLAUSE_SCHEDULE); + + if (c_parser_next_token_is (parser, CPP_NAME)) + { + tree kind = c_parser_peek_token (parser)->value; + const char *p = IDENTIFIER_POINTER (kind); + + switch (p[0]) + { + case 'd': + if (strcmp ("dynamic", p) != 0) + goto invalid_kind; + OMP_CLAUSE_SCHEDULE_KIND (c) = OMP_CLAUSE_SCHEDULE_DYNAMIC; + break; + + case 'g': + if (strcmp ("guided", p) != 0) + goto invalid_kind; + OMP_CLAUSE_SCHEDULE_KIND (c) = OMP_CLAUSE_SCHEDULE_GUIDED; + break; + + case 'r': + if (strcmp ("runtime", p) != 0) + goto invalid_kind; + OMP_CLAUSE_SCHEDULE_KIND (c) = OMP_CLAUSE_SCHEDULE_RUNTIME; + break; + + default: + goto invalid_kind; + } + } + else if (c_parser_next_token_is_keyword (parser, RID_STATIC)) + OMP_CLAUSE_SCHEDULE_KIND (c) = OMP_CLAUSE_SCHEDULE_STATIC; + else if (c_parser_next_token_is_keyword (parser, RID_AUTO)) + OMP_CLAUSE_SCHEDULE_KIND (c) = OMP_CLAUSE_SCHEDULE_AUTO; + else + goto invalid_kind; + + c_parser_consume_token (parser); + if (c_parser_next_token_is (parser, CPP_COMMA)) + { + location_t here; + c_parser_consume_token (parser); + + here = c_parser_peek_token (parser)->location; + t = c_parser_expr_no_commas (parser, NULL).value; + mark_exp_read (t); + t = c_fully_fold (t, false, NULL); + + if (OMP_CLAUSE_SCHEDULE_KIND (c) == OMP_CLAUSE_SCHEDULE_RUNTIME) + error_at (here, "schedule %<runtime%> does not take " + "a %<chunk_size%> parameter"); + else if (OMP_CLAUSE_SCHEDULE_KIND (c) == OMP_CLAUSE_SCHEDULE_AUTO) + error_at (here, + "schedule %<auto%> does not take " + "a %<chunk_size%> parameter"); + else if (TREE_CODE (TREE_TYPE (t)) == INTEGER_TYPE) + OMP_CLAUSE_SCHEDULE_CHUNK_EXPR (c) = t; + else + c_parser_error (parser, "expected integer expression"); + + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); + } + else + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, + "expected %<,%> or %<)%>"); + + check_no_duplicate_clause (list, OMP_CLAUSE_SCHEDULE, "schedule"); + OMP_CLAUSE_CHAIN (c) = list; + return c; + + invalid_kind: + c_parser_error (parser, "invalid schedule kind"); + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, 0); + return list; +} + +/* OpenMP 2.5: + shared ( variable-list ) */ + +static tree +c_parser_omp_clause_shared (c_parser *parser, tree list) +{ + return c_parser_omp_var_list_parens (parser, OMP_CLAUSE_SHARED, list); +} + +/* OpenMP 3.0: + untied */ + +static tree +c_parser_omp_clause_untied (c_parser *parser ATTRIBUTE_UNUSED, tree list) +{ + tree c; + + /* FIXME: Should we allow duplicates? */ + check_no_duplicate_clause (list, OMP_CLAUSE_UNTIED, "untied"); + + c = build_omp_clause (c_parser_peek_token (parser)->location, + OMP_CLAUSE_UNTIED); + OMP_CLAUSE_CHAIN (c) = list; + + return c; +} + +/* Parse all OpenMP clauses. The set clauses allowed by the directive + is a bitmask in MASK. Return the list of clauses found; the result + of clause default goes in *pdefault. */ + +static tree +c_parser_omp_all_clauses (c_parser *parser, unsigned int mask, + const char *where) +{ + tree clauses = NULL; + bool first = true; + + while (c_parser_next_token_is_not (parser, CPP_PRAGMA_EOL)) + { + location_t here; + pragma_omp_clause c_kind; + const char *c_name; + tree prev = clauses; + + if (!first && c_parser_next_token_is (parser, CPP_COMMA)) + c_parser_consume_token (parser); + + first = false; + here = c_parser_peek_token (parser)->location; + c_kind = c_parser_omp_clause_name (parser); + + switch (c_kind) + { + case PRAGMA_OMP_CLAUSE_COLLAPSE: + clauses = c_parser_omp_clause_collapse (parser, clauses); + c_name = "collapse"; + break; + case PRAGMA_OMP_CLAUSE_COPYIN: + clauses = c_parser_omp_clause_copyin (parser, clauses); + c_name = "copyin"; + break; + case PRAGMA_OMP_CLAUSE_COPYPRIVATE: + clauses = c_parser_omp_clause_copyprivate (parser, clauses); + c_name = "copyprivate"; + break; + case PRAGMA_OMP_CLAUSE_DEFAULT: + clauses = c_parser_omp_clause_default (parser, clauses); + c_name = "default"; + break; + case PRAGMA_OMP_CLAUSE_FIRSTPRIVATE: + clauses = c_parser_omp_clause_firstprivate (parser, clauses); + c_name = "firstprivate"; + break; + case PRAGMA_OMP_CLAUSE_FINAL: + clauses = c_parser_omp_clause_final (parser, clauses); + c_name = "final"; + break; + case PRAGMA_OMP_CLAUSE_IF: + clauses = c_parser_omp_clause_if (parser, clauses); + c_name = "if"; + break; + case PRAGMA_OMP_CLAUSE_LASTPRIVATE: + clauses = c_parser_omp_clause_lastprivate (parser, clauses); + c_name = "lastprivate"; + break; + case PRAGMA_OMP_CLAUSE_MERGEABLE: + clauses = c_parser_omp_clause_mergeable (parser, clauses); + c_name = "mergeable"; + break; + case PRAGMA_OMP_CLAUSE_NOWAIT: + clauses = c_parser_omp_clause_nowait (parser, clauses); + c_name = "nowait"; + break; + case PRAGMA_OMP_CLAUSE_NUM_THREADS: + clauses = c_parser_omp_clause_num_threads (parser, clauses); + c_name = "num_threads"; + break; + case PRAGMA_OMP_CLAUSE_ORDERED: + clauses = c_parser_omp_clause_ordered (parser, clauses); + c_name = "ordered"; + break; + case PRAGMA_OMP_CLAUSE_PRIVATE: + clauses = c_parser_omp_clause_private (parser, clauses); + c_name = "private"; + break; + case PRAGMA_OMP_CLAUSE_REDUCTION: + clauses = c_parser_omp_clause_reduction (parser, clauses); + c_name = "reduction"; + break; + case PRAGMA_OMP_CLAUSE_SCHEDULE: + clauses = c_parser_omp_clause_schedule (parser, clauses); + c_name = "schedule"; + break; + case PRAGMA_OMP_CLAUSE_SHARED: + clauses = c_parser_omp_clause_shared (parser, clauses); + c_name = "shared"; + break; + case PRAGMA_OMP_CLAUSE_UNTIED: + clauses = c_parser_omp_clause_untied (parser, clauses); + c_name = "untied"; + break; + default: + c_parser_error (parser, "expected %<#pragma omp%> clause"); + goto saw_error; + } + + if (((mask >> c_kind) & 1) == 0 && !parser->error) + { + /* Remove the invalid clause(s) from the list to avoid + confusing the rest of the compiler. */ + clauses = prev; + error_at (here, "%qs is not valid for %qs", c_name, where); + } + } + + saw_error: + c_parser_skip_to_pragma_eol (parser); + + return c_finish_omp_clauses (clauses); +} + +/* OpenMP 2.5: + structured-block: + statement + + In practice, we're also interested in adding the statement to an + outer node. So it is convenient if we work around the fact that + c_parser_statement calls add_stmt. */ + +static tree +c_parser_omp_structured_block (c_parser *parser) +{ + tree stmt = push_stmt_list (); + c_parser_statement (parser); + return pop_stmt_list (stmt); +} + +/* OpenMP 2.5: + # pragma omp atomic new-line + expression-stmt + + expression-stmt: + x binop= expr | x++ | ++x | x-- | --x + binop: + +, *, -, /, &, ^, |, <<, >> + + where x is an lvalue expression with scalar type. + + OpenMP 3.1: + # pragma omp atomic new-line + update-stmt + + # pragma omp atomic read new-line + read-stmt + + # pragma omp atomic write new-line + write-stmt + + # pragma omp atomic update new-line + update-stmt + + # pragma omp atomic capture new-line + capture-stmt + + # pragma omp atomic capture new-line + capture-block + + read-stmt: + v = x + write-stmt: + x = expr + update-stmt: + expression-stmt | x = x binop expr + capture-stmt: + v = x binop= expr | v = x++ | v = ++x | v = x-- | v = --x + capture-block: + { v = x; update-stmt; } | { update-stmt; v = x; } + + where x and v are lvalue expressions with scalar type. + + LOC is the location of the #pragma token. */ + +static void +c_parser_omp_atomic (location_t loc, c_parser *parser) +{ + tree lhs = NULL_TREE, rhs = NULL_TREE, v = NULL_TREE; + tree lhs1 = NULL_TREE, rhs1 = NULL_TREE; + tree stmt, orig_lhs; + enum tree_code code = OMP_ATOMIC, opcode = NOP_EXPR; + struct c_expr rhs_expr; + bool structured_block = false; + + if (c_parser_next_token_is (parser, CPP_NAME)) + { + const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); + + if (!strcmp (p, "read")) + code = OMP_ATOMIC_READ; + else if (!strcmp (p, "write")) + code = NOP_EXPR; + else if (!strcmp (p, "update")) + code = OMP_ATOMIC; + else if (!strcmp (p, "capture")) + code = OMP_ATOMIC_CAPTURE_NEW; + else + p = NULL; + if (p) + c_parser_consume_token (parser); + } + c_parser_skip_to_pragma_eol (parser); + + switch (code) + { + case OMP_ATOMIC_READ: + case NOP_EXPR: /* atomic write */ + v = c_parser_unary_expression (parser).value; + v = c_fully_fold (v, false, NULL); + if (v == error_mark_node) + goto saw_error; + loc = c_parser_peek_token (parser)->location; + if (!c_parser_require (parser, CPP_EQ, "expected %<=%>")) + goto saw_error; + if (code == NOP_EXPR) + lhs = c_parser_expression (parser).value; + else + lhs = c_parser_unary_expression (parser).value; + lhs = c_fully_fold (lhs, false, NULL); + if (lhs == error_mark_node) + goto saw_error; + if (code == NOP_EXPR) + { + /* atomic write is represented by OMP_ATOMIC with NOP_EXPR + opcode. */ + code = OMP_ATOMIC; + rhs = lhs; + lhs = v; + v = NULL_TREE; + } + goto done; + case OMP_ATOMIC_CAPTURE_NEW: + if (c_parser_next_token_is (parser, CPP_OPEN_BRACE)) + { + c_parser_consume_token (parser); + structured_block = true; + } + else + { + v = c_parser_unary_expression (parser).value; + v = c_fully_fold (v, false, NULL); + if (v == error_mark_node) + goto saw_error; + if (!c_parser_require (parser, CPP_EQ, "expected %<=%>")) + goto saw_error; + } + break; + default: + break; + } + + /* For structured_block case we don't know yet whether + old or new x should be captured. */ +restart: + lhs = c_parser_unary_expression (parser).value; + lhs = c_fully_fold (lhs, false, NULL); + orig_lhs = lhs; + switch (TREE_CODE (lhs)) + { + case ERROR_MARK: + saw_error: + c_parser_skip_to_end_of_block_or_statement (parser); + if (structured_block) + { + if (c_parser_next_token_is (parser, CPP_CLOSE_BRACE)) + c_parser_consume_token (parser); + else if (code == OMP_ATOMIC_CAPTURE_NEW) + { + c_parser_skip_to_end_of_block_or_statement (parser); + if (c_parser_next_token_is (parser, CPP_CLOSE_BRACE)) + c_parser_consume_token (parser); + } + } + return; + + case POSTINCREMENT_EXPR: + if (code == OMP_ATOMIC_CAPTURE_NEW && !structured_block) + code = OMP_ATOMIC_CAPTURE_OLD; + /* FALLTHROUGH */ + case PREINCREMENT_EXPR: + lhs = TREE_OPERAND (lhs, 0); + opcode = PLUS_EXPR; + rhs = integer_one_node; + break; + + case POSTDECREMENT_EXPR: + if (code == OMP_ATOMIC_CAPTURE_NEW && !structured_block) + code = OMP_ATOMIC_CAPTURE_OLD; + /* FALLTHROUGH */ + case PREDECREMENT_EXPR: + lhs = TREE_OPERAND (lhs, 0); + opcode = MINUS_EXPR; + rhs = integer_one_node; + break; + + case COMPOUND_EXPR: + if (TREE_CODE (TREE_OPERAND (lhs, 0)) == SAVE_EXPR + && TREE_CODE (TREE_OPERAND (lhs, 1)) == COMPOUND_EXPR + && TREE_CODE (TREE_OPERAND (TREE_OPERAND (lhs, 1), 0)) == MODIFY_EXPR + && TREE_OPERAND (TREE_OPERAND (lhs, 1), 1) == TREE_OPERAND (lhs, 0) + && TREE_CODE (TREE_TYPE (TREE_OPERAND (TREE_OPERAND + (TREE_OPERAND (lhs, 1), 0), 0))) + == BOOLEAN_TYPE) + /* Undo effects of boolean_increment for post {in,de}crement. */ + lhs = TREE_OPERAND (TREE_OPERAND (lhs, 1), 0); + /* FALLTHRU */ + case MODIFY_EXPR: + if (TREE_CODE (lhs) == MODIFY_EXPR + && TREE_CODE (TREE_TYPE (TREE_OPERAND (lhs, 0))) == BOOLEAN_TYPE) + { + /* Undo effects of boolean_increment. */ + if (integer_onep (TREE_OPERAND (lhs, 1))) + { + /* This is pre or post increment. */ + rhs = TREE_OPERAND (lhs, 1); + lhs = TREE_OPERAND (lhs, 0); + opcode = NOP_EXPR; + if (code == OMP_ATOMIC_CAPTURE_NEW + && !structured_block + && TREE_CODE (orig_lhs) == COMPOUND_EXPR) + code = OMP_ATOMIC_CAPTURE_OLD; + break; + } + if (TREE_CODE (TREE_OPERAND (lhs, 1)) == TRUTH_NOT_EXPR + && TREE_OPERAND (lhs, 0) + == TREE_OPERAND (TREE_OPERAND (lhs, 1), 0)) + { + /* This is pre or post decrement. */ + rhs = TREE_OPERAND (lhs, 1); + lhs = TREE_OPERAND (lhs, 0); + opcode = NOP_EXPR; + if (code == OMP_ATOMIC_CAPTURE_NEW + && !structured_block + && TREE_CODE (orig_lhs) == COMPOUND_EXPR) + code = OMP_ATOMIC_CAPTURE_OLD; + break; + } + } + /* FALLTHRU */ + default: + switch (c_parser_peek_token (parser)->type) + { + case CPP_MULT_EQ: + opcode = MULT_EXPR; + break; + case CPP_DIV_EQ: + opcode = TRUNC_DIV_EXPR; + break; + case CPP_PLUS_EQ: + opcode = PLUS_EXPR; + break; + case CPP_MINUS_EQ: + opcode = MINUS_EXPR; + break; + case CPP_LSHIFT_EQ: + opcode = LSHIFT_EXPR; + break; + case CPP_RSHIFT_EQ: + opcode = RSHIFT_EXPR; + break; + case CPP_AND_EQ: + opcode = BIT_AND_EXPR; + break; + case CPP_OR_EQ: + opcode = BIT_IOR_EXPR; + break; + case CPP_XOR_EQ: + opcode = BIT_XOR_EXPR; + break; + case CPP_EQ: + if (structured_block || code == OMP_ATOMIC) + { + location_t aloc = c_parser_peek_token (parser)->location; + location_t rhs_loc; + enum c_parser_prec oprec = PREC_NONE; + + c_parser_consume_token (parser); + rhs1 = c_parser_unary_expression (parser).value; + rhs1 = c_fully_fold (rhs1, false, NULL); + if (rhs1 == error_mark_node) + goto saw_error; + switch (c_parser_peek_token (parser)->type) + { + case CPP_SEMICOLON: + if (code == OMP_ATOMIC_CAPTURE_NEW) + { + code = OMP_ATOMIC_CAPTURE_OLD; + v = lhs; + lhs = NULL_TREE; + lhs1 = rhs1; + rhs1 = NULL_TREE; + c_parser_consume_token (parser); + goto restart; + } + c_parser_error (parser, + "invalid form of %<#pragma omp atomic%>"); + goto saw_error; + case CPP_MULT: + opcode = MULT_EXPR; + oprec = PREC_MULT; + break; + case CPP_DIV: + opcode = TRUNC_DIV_EXPR; + oprec = PREC_MULT; + break; + case CPP_PLUS: + opcode = PLUS_EXPR; + oprec = PREC_ADD; + break; + case CPP_MINUS: + opcode = MINUS_EXPR; + oprec = PREC_ADD; + break; + case CPP_LSHIFT: + opcode = LSHIFT_EXPR; + oprec = PREC_SHIFT; + break; + case CPP_RSHIFT: + opcode = RSHIFT_EXPR; + oprec = PREC_SHIFT; + break; + case CPP_AND: + opcode = BIT_AND_EXPR; + oprec = PREC_BITAND; + break; + case CPP_OR: + opcode = BIT_IOR_EXPR; + oprec = PREC_BITOR; + break; + case CPP_XOR: + opcode = BIT_XOR_EXPR; + oprec = PREC_BITXOR; + break; + default: + c_parser_error (parser, + "invalid operator for %<#pragma omp atomic%>"); + goto saw_error; + } + loc = aloc; + c_parser_consume_token (parser); + rhs_loc = c_parser_peek_token (parser)->location; + if (commutative_tree_code (opcode)) + oprec = (enum c_parser_prec) (oprec - 1); + rhs_expr = c_parser_binary_expression (parser, NULL, oprec); + rhs_expr = default_function_array_read_conversion (rhs_loc, + rhs_expr); + rhs = rhs_expr.value; + rhs = c_fully_fold (rhs, false, NULL); + goto stmt_done; + } + /* FALLTHROUGH */ + default: + c_parser_error (parser, + "invalid operator for %<#pragma omp atomic%>"); + goto saw_error; + } + + /* Arrange to pass the location of the assignment operator to + c_finish_omp_atomic. */ + loc = c_parser_peek_token (parser)->location; + c_parser_consume_token (parser); + { + location_t rhs_loc = c_parser_peek_token (parser)->location; + rhs_expr = c_parser_expression (parser); + rhs_expr = default_function_array_read_conversion (rhs_loc, rhs_expr); + } + rhs = rhs_expr.value; + rhs = c_fully_fold (rhs, false, NULL); + break; + } +stmt_done: + if (structured_block && code == OMP_ATOMIC_CAPTURE_NEW) + { + if (!c_parser_require (parser, CPP_SEMICOLON, "expected %<;%>")) + goto saw_error; + v = c_parser_unary_expression (parser).value; + v = c_fully_fold (v, false, NULL); + if (v == error_mark_node) + goto saw_error; + if (!c_parser_require (parser, CPP_EQ, "expected %<=%>")) + goto saw_error; + lhs1 = c_parser_unary_expression (parser).value; + lhs1 = c_fully_fold (lhs1, false, NULL); + if (lhs1 == error_mark_node) + goto saw_error; + } + if (structured_block) + { + c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>"); + c_parser_require (parser, CPP_CLOSE_BRACE, "expected %<}%>"); + } +done: + stmt = c_finish_omp_atomic (loc, code, opcode, lhs, rhs, v, lhs1, rhs1); + if (stmt != error_mark_node) + add_stmt (stmt); + + if (!structured_block) + c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>"); +} + + +/* OpenMP 2.5: + # pragma omp barrier new-line +*/ + +static void +c_parser_omp_barrier (c_parser *parser) +{ + location_t loc = c_parser_peek_token (parser)->location; + c_parser_consume_pragma (parser); + c_parser_skip_to_pragma_eol (parser); + + c_finish_omp_barrier (loc); +} + +/* OpenMP 2.5: + # pragma omp critical [(name)] new-line + structured-block + + LOC is the location of the #pragma itself. */ + +static tree +c_parser_omp_critical (location_t loc, c_parser *parser) +{ + tree stmt, name = NULL; + + if (c_parser_next_token_is (parser, CPP_OPEN_PAREN)) + { + c_parser_consume_token (parser); + if (c_parser_next_token_is (parser, CPP_NAME)) + { + name = c_parser_peek_token (parser)->value; + c_parser_consume_token (parser); + c_parser_require (parser, CPP_CLOSE_PAREN, "expected %<)%>"); + } + else + c_parser_error (parser, "expected identifier"); + } + else if (c_parser_next_token_is_not (parser, CPP_PRAGMA_EOL)) + c_parser_error (parser, "expected %<(%> or end of line"); + c_parser_skip_to_pragma_eol (parser); + + stmt = c_parser_omp_structured_block (parser); + return c_finish_omp_critical (loc, stmt, name); +} + +/* OpenMP 2.5: + # pragma omp flush flush-vars[opt] new-line + + flush-vars: + ( variable-list ) */ + +static void +c_parser_omp_flush (c_parser *parser) +{ + location_t loc = c_parser_peek_token (parser)->location; + c_parser_consume_pragma (parser); + if (c_parser_next_token_is (parser, CPP_OPEN_PAREN)) + c_parser_omp_var_list_parens (parser, OMP_CLAUSE_ERROR, NULL); + else if (c_parser_next_token_is_not (parser, CPP_PRAGMA_EOL)) + c_parser_error (parser, "expected %<(%> or end of line"); + c_parser_skip_to_pragma_eol (parser); + + c_finish_omp_flush (loc); +} + +/* Parse the restricted form of the for statement allowed by OpenMP. + The real trick here is to determine the loop control variable early + so that we can push a new decl if necessary to make it private. + LOC is the location of the OMP in "#pragma omp". */ + +static tree +c_parser_omp_for_loop (location_t loc, + c_parser *parser, tree clauses, tree *par_clauses) +{ + tree decl, cond, incr, save_break, save_cont, body, init, stmt, cl; + tree declv, condv, incrv, initv, ret = NULL; + bool fail = false, open_brace_parsed = false; + int i, collapse = 1, nbraces = 0; + location_t for_loc; + VEC(tree,gc) *for_block = make_tree_vector (); + + for (cl = clauses; cl; cl = OMP_CLAUSE_CHAIN (cl)) + if (OMP_CLAUSE_CODE (cl) == OMP_CLAUSE_COLLAPSE) + collapse = tree_low_cst (OMP_CLAUSE_COLLAPSE_EXPR (cl), 0); + + gcc_assert (collapse >= 1); + + declv = make_tree_vec (collapse); + initv = make_tree_vec (collapse); + condv = make_tree_vec (collapse); + incrv = make_tree_vec (collapse); + + if (!c_parser_next_token_is_keyword (parser, RID_FOR)) + { + c_parser_error (parser, "for statement expected"); + return NULL; + } + for_loc = c_parser_peek_token (parser)->location; + c_parser_consume_token (parser); + + for (i = 0; i < collapse; i++) + { + int bracecount = 0; + + if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) + goto pop_scopes; + + /* Parse the initialization declaration or expression. */ + if (c_parser_next_tokens_start_declaration (parser)) + { + if (i > 0) + VEC_safe_push (tree, gc, for_block, c_begin_compound_stmt (true)); + c_parser_declaration_or_fndef (parser, true, true, true, true, true, NULL); + decl = check_for_loop_decls (for_loc, flag_isoc99); + if (decl == NULL) + goto error_init; + if (DECL_INITIAL (decl) == error_mark_node) + decl = error_mark_node; + init = decl; + } + else if (c_parser_next_token_is (parser, CPP_NAME) + && c_parser_peek_2nd_token (parser)->type == CPP_EQ) + { + struct c_expr decl_exp; + struct c_expr init_exp; + location_t init_loc; + + decl_exp = c_parser_postfix_expression (parser); + decl = decl_exp.value; + + c_parser_require (parser, CPP_EQ, "expected %<=%>"); + + init_loc = c_parser_peek_token (parser)->location; + init_exp = c_parser_expr_no_commas (parser, NULL); + init_exp = default_function_array_read_conversion (init_loc, + init_exp); + init = build_modify_expr (init_loc, decl, decl_exp.original_type, + NOP_EXPR, init_loc, init_exp.value, + init_exp.original_type); + init = c_process_expr_stmt (init_loc, init); + + c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>"); + } + else + { + error_init: + c_parser_error (parser, + "expected iteration declaration or initialization"); + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, + "expected %<)%>"); + fail = true; + goto parse_next; + } + + /* Parse the loop condition. */ + cond = NULL_TREE; + if (c_parser_next_token_is_not (parser, CPP_SEMICOLON)) + { + location_t cond_loc = c_parser_peek_token (parser)->location; + struct c_expr cond_expr = c_parser_binary_expression (parser, NULL, + PREC_NONE); + + cond = cond_expr.value; + cond = c_objc_common_truthvalue_conversion (cond_loc, cond); + cond = c_fully_fold (cond, false, NULL); + switch (cond_expr.original_code) + { + case GT_EXPR: + case GE_EXPR: + case LT_EXPR: + case LE_EXPR: + break; + default: + /* Can't be cond = error_mark_node, because we want to preserve + the location until c_finish_omp_for. */ + cond = build1 (NOP_EXPR, boolean_type_node, error_mark_node); + break; + } + protected_set_expr_location (cond, cond_loc); + } + c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>"); + + /* Parse the increment expression. */ + incr = NULL_TREE; + if (c_parser_next_token_is_not (parser, CPP_CLOSE_PAREN)) + { + location_t incr_loc = c_parser_peek_token (parser)->location; + + incr = c_process_expr_stmt (incr_loc, + c_parser_expression (parser).value); + } + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); + + if (decl == NULL || decl == error_mark_node || init == error_mark_node) + fail = true; + else + { + TREE_VEC_ELT (declv, i) = decl; + TREE_VEC_ELT (initv, i) = init; + TREE_VEC_ELT (condv, i) = cond; + TREE_VEC_ELT (incrv, i) = incr; + } + + parse_next: + if (i == collapse - 1) + break; + + /* FIXME: OpenMP 3.0 draft isn't very clear on what exactly is allowed + in between the collapsed for loops to be still considered perfectly + nested. Hopefully the final version clarifies this. + For now handle (multiple) {'s and empty statements. */ + do + { + if (c_parser_next_token_is_keyword (parser, RID_FOR)) + { + c_parser_consume_token (parser); + break; + } + else if (c_parser_next_token_is (parser, CPP_OPEN_BRACE)) + { + c_parser_consume_token (parser); + bracecount++; + } + else if (bracecount + && c_parser_next_token_is (parser, CPP_SEMICOLON)) + c_parser_consume_token (parser); + else + { + c_parser_error (parser, "not enough perfectly nested loops"); + if (bracecount) + { + open_brace_parsed = true; + bracecount--; + } + fail = true; + collapse = 0; + break; + } + } + while (1); + + nbraces += bracecount; + } + + save_break = c_break_label; + c_break_label = size_one_node; + save_cont = c_cont_label; + c_cont_label = NULL_TREE; + body = push_stmt_list (); + + if (open_brace_parsed) + { + location_t here = c_parser_peek_token (parser)->location; + stmt = c_begin_compound_stmt (true); + c_parser_compound_statement_nostart (parser); + add_stmt (c_end_compound_stmt (here, stmt, true)); + } + else + add_stmt (c_parser_c99_block_statement (parser)); + if (c_cont_label) + { + tree t = build1 (LABEL_EXPR, void_type_node, c_cont_label); + SET_EXPR_LOCATION (t, loc); + add_stmt (t); + } + + body = pop_stmt_list (body); + c_break_label = save_break; + c_cont_label = save_cont; + + while (nbraces) + { + if (c_parser_next_token_is (parser, CPP_CLOSE_BRACE)) + { + c_parser_consume_token (parser); + nbraces--; + } + else if (c_parser_next_token_is (parser, CPP_SEMICOLON)) + c_parser_consume_token (parser); + else + { + c_parser_error (parser, "collapsed loops not perfectly nested"); + while (nbraces) + { + location_t here = c_parser_peek_token (parser)->location; + stmt = c_begin_compound_stmt (true); + add_stmt (body); + c_parser_compound_statement_nostart (parser); + body = c_end_compound_stmt (here, stmt, true); + nbraces--; + } + goto pop_scopes; + } + } + + /* Only bother calling c_finish_omp_for if we haven't already generated + an error from the initialization parsing. */ + if (!fail) + { + stmt = c_finish_omp_for (loc, declv, initv, condv, incrv, body, NULL); + if (stmt) + { + if (par_clauses != NULL) + { + tree *c; + for (c = par_clauses; *c ; ) + if (OMP_CLAUSE_CODE (*c) != OMP_CLAUSE_FIRSTPRIVATE + && OMP_CLAUSE_CODE (*c) != OMP_CLAUSE_LASTPRIVATE) + c = &OMP_CLAUSE_CHAIN (*c); + else + { + for (i = 0; i < collapse; i++) + if (TREE_VEC_ELT (declv, i) == OMP_CLAUSE_DECL (*c)) + break; + if (i == collapse) + c = &OMP_CLAUSE_CHAIN (*c); + else if (OMP_CLAUSE_CODE (*c) == OMP_CLAUSE_FIRSTPRIVATE) + { + error_at (loc, + "iteration variable %qD should not be firstprivate", + OMP_CLAUSE_DECL (*c)); + *c = OMP_CLAUSE_CHAIN (*c); + } + else + { + /* Copy lastprivate (decl) clause to OMP_FOR_CLAUSES, + change it to shared (decl) in + OMP_PARALLEL_CLAUSES. */ + tree l = build_omp_clause (OMP_CLAUSE_LOCATION (*c), + OMP_CLAUSE_LASTPRIVATE); + OMP_CLAUSE_DECL (l) = OMP_CLAUSE_DECL (*c); + OMP_CLAUSE_CHAIN (l) = clauses; + clauses = l; + OMP_CLAUSE_SET_CODE (*c, OMP_CLAUSE_SHARED); + } + } + } + OMP_FOR_CLAUSES (stmt) = clauses; + } + ret = stmt; + } +pop_scopes: + while (!VEC_empty (tree, for_block)) + { + /* FIXME diagnostics: LOC below should be the actual location of + this particular for block. We need to build a list of + locations to go along with FOR_BLOCK. */ + stmt = c_end_compound_stmt (loc, VEC_pop (tree, for_block), true); + add_stmt (stmt); + } + release_tree_vector (for_block); + return ret; +} + +/* OpenMP 2.5: + #pragma omp for for-clause[optseq] new-line + for-loop + + LOC is the location of the #pragma token. +*/ + +#define OMP_FOR_CLAUSE_MASK \ + ( (1u << PRAGMA_OMP_CLAUSE_PRIVATE) \ + | (1u << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE) \ + | (1u << PRAGMA_OMP_CLAUSE_LASTPRIVATE) \ + | (1u << PRAGMA_OMP_CLAUSE_REDUCTION) \ + | (1u << PRAGMA_OMP_CLAUSE_ORDERED) \ + | (1u << PRAGMA_OMP_CLAUSE_SCHEDULE) \ + | (1u << PRAGMA_OMP_CLAUSE_COLLAPSE) \ + | (1u << PRAGMA_OMP_CLAUSE_NOWAIT)) + +static tree +c_parser_omp_for (location_t loc, c_parser *parser) +{ + tree block, clauses, ret; + + clauses = c_parser_omp_all_clauses (parser, OMP_FOR_CLAUSE_MASK, + "#pragma omp for"); + + block = c_begin_compound_stmt (true); + ret = c_parser_omp_for_loop (loc, parser, clauses, NULL); + block = c_end_compound_stmt (loc, block, true); + add_stmt (block); + + return ret; +} + +/* OpenMP 2.5: + # pragma omp master new-line + structured-block + + LOC is the location of the #pragma token. +*/ + +static tree +c_parser_omp_master (location_t loc, c_parser *parser) +{ + c_parser_skip_to_pragma_eol (parser); + return c_finish_omp_master (loc, c_parser_omp_structured_block (parser)); +} + +/* OpenMP 2.5: + # pragma omp ordered new-line + structured-block + + LOC is the location of the #pragma itself. +*/ + +static tree +c_parser_omp_ordered (location_t loc, c_parser *parser) +{ + c_parser_skip_to_pragma_eol (parser); + return c_finish_omp_ordered (loc, c_parser_omp_structured_block (parser)); +} + +/* OpenMP 2.5: + + section-scope: + { section-sequence } + + section-sequence: + section-directive[opt] structured-block + section-sequence section-directive structured-block + + SECTIONS_LOC is the location of the #pragma omp sections. */ + +static tree +c_parser_omp_sections_scope (location_t sections_loc, c_parser *parser) +{ + tree stmt, substmt; + bool error_suppress = false; + location_t loc; + + loc = c_parser_peek_token (parser)->location; + if (!c_parser_require (parser, CPP_OPEN_BRACE, "expected %<{%>")) + { + /* Avoid skipping until the end of the block. */ + parser->error = false; + return NULL_TREE; + } + + stmt = push_stmt_list (); + + if (c_parser_peek_token (parser)->pragma_kind != PRAGMA_OMP_SECTION) + { + substmt = push_stmt_list (); + + while (1) + { + c_parser_statement (parser); + + if (c_parser_peek_token (parser)->pragma_kind == PRAGMA_OMP_SECTION) + break; + if (c_parser_next_token_is (parser, CPP_CLOSE_BRACE)) + break; + if (c_parser_next_token_is (parser, CPP_EOF)) + break; + } + + substmt = pop_stmt_list (substmt); + substmt = build1 (OMP_SECTION, void_type_node, substmt); + SET_EXPR_LOCATION (substmt, loc); + add_stmt (substmt); + } + + while (1) + { + if (c_parser_next_token_is (parser, CPP_CLOSE_BRACE)) + break; + if (c_parser_next_token_is (parser, CPP_EOF)) + break; + + loc = c_parser_peek_token (parser)->location; + if (c_parser_peek_token (parser)->pragma_kind == PRAGMA_OMP_SECTION) + { + c_parser_consume_pragma (parser); + c_parser_skip_to_pragma_eol (parser); + error_suppress = false; + } + else if (!error_suppress) + { + error_at (loc, "expected %<#pragma omp section%> or %<}%>"); + error_suppress = true; + } + + substmt = c_parser_omp_structured_block (parser); + substmt = build1 (OMP_SECTION, void_type_node, substmt); + SET_EXPR_LOCATION (substmt, loc); + add_stmt (substmt); + } + c_parser_skip_until_found (parser, CPP_CLOSE_BRACE, + "expected %<#pragma omp section%> or %<}%>"); + + substmt = pop_stmt_list (stmt); + + stmt = make_node (OMP_SECTIONS); + SET_EXPR_LOCATION (stmt, sections_loc); + TREE_TYPE (stmt) = void_type_node; + OMP_SECTIONS_BODY (stmt) = substmt; + + return add_stmt (stmt); +} + +/* OpenMP 2.5: + # pragma omp sections sections-clause[optseq] newline + sections-scope + + LOC is the location of the #pragma token. +*/ + +#define OMP_SECTIONS_CLAUSE_MASK \ + ( (1u << PRAGMA_OMP_CLAUSE_PRIVATE) \ + | (1u << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE) \ + | (1u << PRAGMA_OMP_CLAUSE_LASTPRIVATE) \ + | (1u << PRAGMA_OMP_CLAUSE_REDUCTION) \ + | (1u << PRAGMA_OMP_CLAUSE_NOWAIT)) + +static tree +c_parser_omp_sections (location_t loc, c_parser *parser) +{ + tree block, clauses, ret; + + clauses = c_parser_omp_all_clauses (parser, OMP_SECTIONS_CLAUSE_MASK, + "#pragma omp sections"); + + block = c_begin_compound_stmt (true); + ret = c_parser_omp_sections_scope (loc, parser); + if (ret) + OMP_SECTIONS_CLAUSES (ret) = clauses; + block = c_end_compound_stmt (loc, block, true); + add_stmt (block); + + return ret; +} + +/* OpenMP 2.5: + # pragma parallel parallel-clause new-line + # pragma parallel for parallel-for-clause new-line + # pragma parallel sections parallel-sections-clause new-line + + LOC is the location of the #pragma token. +*/ + +#define OMP_PARALLEL_CLAUSE_MASK \ + ( (1u << PRAGMA_OMP_CLAUSE_IF) \ + | (1u << PRAGMA_OMP_CLAUSE_PRIVATE) \ + | (1u << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE) \ + | (1u << PRAGMA_OMP_CLAUSE_DEFAULT) \ + | (1u << PRAGMA_OMP_CLAUSE_SHARED) \ + | (1u << PRAGMA_OMP_CLAUSE_COPYIN) \ + | (1u << PRAGMA_OMP_CLAUSE_REDUCTION) \ + | (1u << PRAGMA_OMP_CLAUSE_NUM_THREADS)) + +static tree +c_parser_omp_parallel (location_t loc, c_parser *parser) +{ + enum pragma_kind p_kind = PRAGMA_OMP_PARALLEL; + const char *p_name = "#pragma omp parallel"; + tree stmt, clauses, par_clause, ws_clause, block; + unsigned int mask = OMP_PARALLEL_CLAUSE_MASK; + + if (c_parser_next_token_is_keyword (parser, RID_FOR)) + { + c_parser_consume_token (parser); + p_kind = PRAGMA_OMP_PARALLEL_FOR; + p_name = "#pragma omp parallel for"; + mask |= OMP_FOR_CLAUSE_MASK; + mask &= ~(1u << PRAGMA_OMP_CLAUSE_NOWAIT); + } + else if (c_parser_next_token_is (parser, CPP_NAME)) + { + const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); + if (strcmp (p, "sections") == 0) + { + c_parser_consume_token (parser); + p_kind = PRAGMA_OMP_PARALLEL_SECTIONS; + p_name = "#pragma omp parallel sections"; + mask |= OMP_SECTIONS_CLAUSE_MASK; + mask &= ~(1u << PRAGMA_OMP_CLAUSE_NOWAIT); + } + } + + clauses = c_parser_omp_all_clauses (parser, mask, p_name); + + switch (p_kind) + { + case PRAGMA_OMP_PARALLEL: + block = c_begin_omp_parallel (); + c_parser_statement (parser); + stmt = c_finish_omp_parallel (loc, clauses, block); + break; + + case PRAGMA_OMP_PARALLEL_FOR: + block = c_begin_omp_parallel (); + c_split_parallel_clauses (loc, clauses, &par_clause, &ws_clause); + c_parser_omp_for_loop (loc, parser, ws_clause, &par_clause); + stmt = c_finish_omp_parallel (loc, par_clause, block); + OMP_PARALLEL_COMBINED (stmt) = 1; + break; + + case PRAGMA_OMP_PARALLEL_SECTIONS: + block = c_begin_omp_parallel (); + c_split_parallel_clauses (loc, clauses, &par_clause, &ws_clause); + stmt = c_parser_omp_sections_scope (loc, parser); + if (stmt) + OMP_SECTIONS_CLAUSES (stmt) = ws_clause; + stmt = c_finish_omp_parallel (loc, par_clause, block); + OMP_PARALLEL_COMBINED (stmt) = 1; + break; + + default: + gcc_unreachable (); + } + + return stmt; +} + +/* OpenMP 2.5: + # pragma omp single single-clause[optseq] new-line + structured-block + + LOC is the location of the #pragma. +*/ + +#define OMP_SINGLE_CLAUSE_MASK \ + ( (1u << PRAGMA_OMP_CLAUSE_PRIVATE) \ + | (1u << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE) \ + | (1u << PRAGMA_OMP_CLAUSE_COPYPRIVATE) \ + | (1u << PRAGMA_OMP_CLAUSE_NOWAIT)) + +static tree +c_parser_omp_single (location_t loc, c_parser *parser) +{ + tree stmt = make_node (OMP_SINGLE); + SET_EXPR_LOCATION (stmt, loc); + TREE_TYPE (stmt) = void_type_node; + + OMP_SINGLE_CLAUSES (stmt) + = c_parser_omp_all_clauses (parser, OMP_SINGLE_CLAUSE_MASK, + "#pragma omp single"); + OMP_SINGLE_BODY (stmt) = c_parser_omp_structured_block (parser); + + return add_stmt (stmt); +} + +/* OpenMP 3.0: + # pragma omp task task-clause[optseq] new-line + + LOC is the location of the #pragma. +*/ + +#define OMP_TASK_CLAUSE_MASK \ + ( (1u << PRAGMA_OMP_CLAUSE_IF) \ + | (1u << PRAGMA_OMP_CLAUSE_UNTIED) \ + | (1u << PRAGMA_OMP_CLAUSE_DEFAULT) \ + | (1u << PRAGMA_OMP_CLAUSE_PRIVATE) \ + | (1u << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE) \ + | (1u << PRAGMA_OMP_CLAUSE_SHARED) \ + | (1u << PRAGMA_OMP_CLAUSE_FINAL) \ + | (1u << PRAGMA_OMP_CLAUSE_MERGEABLE)) + +static tree +c_parser_omp_task (location_t loc, c_parser *parser) +{ + tree clauses, block; + + clauses = c_parser_omp_all_clauses (parser, OMP_TASK_CLAUSE_MASK, + "#pragma omp task"); + + block = c_begin_omp_task (); + c_parser_statement (parser); + return c_finish_omp_task (loc, clauses, block); +} + +/* OpenMP 3.0: + # pragma omp taskwait new-line +*/ + +static void +c_parser_omp_taskwait (c_parser *parser) +{ + location_t loc = c_parser_peek_token (parser)->location; + c_parser_consume_pragma (parser); + c_parser_skip_to_pragma_eol (parser); + + c_finish_omp_taskwait (loc); +} + +/* OpenMP 3.1: + # pragma omp taskyield new-line +*/ + +static void +c_parser_omp_taskyield (c_parser *parser) +{ + location_t loc = c_parser_peek_token (parser)->location; + c_parser_consume_pragma (parser); + c_parser_skip_to_pragma_eol (parser); + + c_finish_omp_taskyield (loc); +} + +/* Main entry point to parsing most OpenMP pragmas. */ + +static void +c_parser_omp_construct (c_parser *parser) +{ + enum pragma_kind p_kind; + location_t loc; + tree stmt; + + loc = c_parser_peek_token (parser)->location; + p_kind = c_parser_peek_token (parser)->pragma_kind; + c_parser_consume_pragma (parser); + + switch (p_kind) + { + case PRAGMA_OMP_ATOMIC: + c_parser_omp_atomic (loc, parser); + return; + case PRAGMA_OMP_CRITICAL: + stmt = c_parser_omp_critical (loc, parser); + break; + case PRAGMA_OMP_FOR: + stmt = c_parser_omp_for (loc, parser); + break; + case PRAGMA_OMP_MASTER: + stmt = c_parser_omp_master (loc, parser); + break; + case PRAGMA_OMP_ORDERED: + stmt = c_parser_omp_ordered (loc, parser); + break; + case PRAGMA_OMP_PARALLEL: + stmt = c_parser_omp_parallel (loc, parser); + break; + case PRAGMA_OMP_SECTIONS: + stmt = c_parser_omp_sections (loc, parser); + break; + case PRAGMA_OMP_SINGLE: + stmt = c_parser_omp_single (loc, parser); + break; + case PRAGMA_OMP_TASK: + stmt = c_parser_omp_task (loc, parser); + break; + default: + gcc_unreachable (); + } + + if (stmt) + gcc_assert (EXPR_LOCATION (stmt) != UNKNOWN_LOCATION); +} + + +/* OpenMP 2.5: + # pragma omp threadprivate (variable-list) */ + +static void +c_parser_omp_threadprivate (c_parser *parser) +{ + tree vars, t; + location_t loc; + + c_parser_consume_pragma (parser); + loc = c_parser_peek_token (parser)->location; + vars = c_parser_omp_var_list_parens (parser, OMP_CLAUSE_ERROR, NULL); + + /* Mark every variable in VARS to be assigned thread local storage. */ + for (t = vars; t; t = TREE_CHAIN (t)) + { + tree v = TREE_PURPOSE (t); + + /* FIXME diagnostics: Ideally we should keep individual + locations for all the variables in the var list to make the + following errors more precise. Perhaps + c_parser_omp_var_list_parens() should construct a list of + locations to go along with the var list. */ + + /* If V had already been marked threadprivate, it doesn't matter + whether it had been used prior to this point. */ + if (TREE_CODE (v) != VAR_DECL) + error_at (loc, "%qD is not a variable", v); + else if (TREE_USED (v) && !C_DECL_THREADPRIVATE_P (v)) + error_at (loc, "%qE declared %<threadprivate%> after first use", v); + else if (! TREE_STATIC (v) && ! DECL_EXTERNAL (v)) + error_at (loc, "automatic variable %qE cannot be %<threadprivate%>", v); + else if (TREE_TYPE (v) == error_mark_node) + ; + else if (! COMPLETE_TYPE_P (TREE_TYPE (v))) + error_at (loc, "%<threadprivate%> %qE has incomplete type", v); + else + { + if (! DECL_THREAD_LOCAL_P (v)) + { + DECL_TLS_MODEL (v) = decl_default_tls_model (v); + /* If rtl has been already set for this var, call + make_decl_rtl once again, so that encode_section_info + has a chance to look at the new decl flags. */ + if (DECL_RTL_SET_P (v)) + make_decl_rtl (v); + } + C_DECL_THREADPRIVATE_P (v) = 1; + } + } + + c_parser_skip_to_pragma_eol (parser); +} + +/* Parse a transaction attribute (GCC Extension). + + transaction-attribute: + attributes + [ [ any-word ] ] + + The transactional memory language description is written for C++, + and uses the C++0x attribute syntax. For compatibility, allow the + bracket style for transactions in C as well. */ + +static tree +c_parser_transaction_attributes (c_parser *parser) +{ + tree attr_name, attr = NULL; + + if (c_parser_next_token_is_keyword (parser, RID_ATTRIBUTE)) + return c_parser_attributes (parser); + + if (!c_parser_next_token_is (parser, CPP_OPEN_SQUARE)) + return NULL_TREE; + c_parser_consume_token (parser); + if (!c_parser_require (parser, CPP_OPEN_SQUARE, "expected %<[%>")) + goto error1; + + attr_name = c_parser_attribute_any_word (parser); + if (attr_name) + { + c_parser_consume_token (parser); + attr = build_tree_list (attr_name, NULL_TREE); + } + else + c_parser_error (parser, "expected identifier"); + + c_parser_skip_until_found (parser, CPP_CLOSE_SQUARE, "expected %<]%>"); + error1: + c_parser_skip_until_found (parser, CPP_CLOSE_SQUARE, "expected %<]%>"); + return attr; +} + +/* Parse a __transaction_atomic or __transaction_relaxed statement + (GCC Extension). + + transaction-statement: + __transaction_atomic transaction-attribute[opt] compound-statement + __transaction_relaxed compound-statement + + Note that the only valid attribute is: "outer". +*/ + +static tree +c_parser_transaction (c_parser *parser, enum rid keyword) +{ + unsigned int old_in = parser->in_transaction; + unsigned int this_in = 1, new_in; + location_t loc = c_parser_peek_token (parser)->location; + tree stmt, attrs; + + gcc_assert ((keyword == RID_TRANSACTION_ATOMIC + || keyword == RID_TRANSACTION_RELAXED) + && c_parser_next_token_is_keyword (parser, keyword)); + c_parser_consume_token (parser); + + if (keyword == RID_TRANSACTION_RELAXED) + this_in |= TM_STMT_ATTR_RELAXED; + else + { + attrs = c_parser_transaction_attributes (parser); + if (attrs) + this_in |= parse_tm_stmt_attr (attrs, TM_STMT_ATTR_OUTER); + } + + /* Keep track if we're in the lexical scope of an outer transaction. */ + new_in = this_in | (old_in & TM_STMT_ATTR_OUTER); + + parser->in_transaction = new_in; + stmt = c_parser_compound_statement (parser); + parser->in_transaction = old_in; + + if (flag_tm) + stmt = c_finish_transaction (loc, stmt, this_in); + else + error_at (loc, (keyword == RID_TRANSACTION_ATOMIC ? + "%<__transaction_atomic%> without transactional memory support enabled" + : "%<__transaction_relaxed %> " + "without transactional memory support enabled")); + + return stmt; +} + +/* Parse a __transaction_atomic or __transaction_relaxed expression + (GCC Extension). + + transaction-expression: + __transaction_atomic ( expression ) + __transaction_relaxed ( expression ) +*/ + +static struct c_expr +c_parser_transaction_expression (c_parser *parser, enum rid keyword) +{ + struct c_expr ret; + unsigned int old_in = parser->in_transaction; + unsigned int this_in = 1; + location_t loc = c_parser_peek_token (parser)->location; + tree attrs; + + gcc_assert ((keyword == RID_TRANSACTION_ATOMIC + || keyword == RID_TRANSACTION_RELAXED) + && c_parser_next_token_is_keyword (parser, keyword)); + c_parser_consume_token (parser); + + if (keyword == RID_TRANSACTION_RELAXED) + this_in |= TM_STMT_ATTR_RELAXED; + else + { + attrs = c_parser_transaction_attributes (parser); + if (attrs) + this_in |= parse_tm_stmt_attr (attrs, 0); + } + + parser->in_transaction = this_in; + if (c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) + { + tree expr = c_parser_expression (parser).value; + ret.original_type = TREE_TYPE (expr); + ret.value = build1 (TRANSACTION_EXPR, ret.original_type, expr); + if (this_in & TM_STMT_ATTR_RELAXED) + TRANSACTION_EXPR_RELAXED (ret.value) = 1; + SET_EXPR_LOCATION (ret.value, loc); + ret.original_code = TRANSACTION_EXPR; + if (!c_parser_require (parser, CPP_CLOSE_PAREN, "expected %<)%>")) + { + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL); + goto error; + } + } + else + { + error: + ret.value = error_mark_node; + ret.original_code = ERROR_MARK; + ret.original_type = NULL; + } + parser->in_transaction = old_in; + + if (!flag_tm) + error_at (loc, (keyword == RID_TRANSACTION_ATOMIC ? + "%<__transaction_atomic%> without transactional memory support enabled" + : "%<__transaction_relaxed %> " + "without transactional memory support enabled")); + + return ret; +} + +/* Parse a __transaction_cancel statement (GCC Extension). + + transaction-cancel-statement: + __transaction_cancel transaction-attribute[opt] ; + + Note that the only valid attribute is "outer". +*/ + +static tree +c_parser_transaction_cancel(c_parser *parser) +{ + location_t loc = c_parser_peek_token (parser)->location; + tree attrs; + bool is_outer = false; + + gcc_assert (c_parser_next_token_is_keyword (parser, RID_TRANSACTION_CANCEL)); + c_parser_consume_token (parser); + + attrs = c_parser_transaction_attributes (parser); + if (attrs) + is_outer = (parse_tm_stmt_attr (attrs, TM_STMT_ATTR_OUTER) != 0); + + if (!flag_tm) + { + error_at (loc, "%<__transaction_cancel%> without " + "transactional memory support enabled"); + goto ret_error; + } + else if (parser->in_transaction & TM_STMT_ATTR_RELAXED) + { + error_at (loc, "%<__transaction_cancel%> within a " + "%<__transaction_relaxed%>"); + goto ret_error; + } + else if (is_outer) + { + if ((parser->in_transaction & TM_STMT_ATTR_OUTER) == 0 + && !is_tm_may_cancel_outer (current_function_decl)) + { + error_at (loc, "outer %<__transaction_cancel%> not " + "within outer %<__transaction_atomic%>"); + error_at (loc, " or a %<transaction_may_cancel_outer%> function"); + goto ret_error; + } + } + else if (parser->in_transaction == 0) + { + error_at (loc, "%<__transaction_cancel%> not within " + "%<__transaction_atomic%>"); + goto ret_error; + } + + return add_stmt (build_tm_abort_call (loc, is_outer)); + + ret_error: + return build1 (NOP_EXPR, void_type_node, error_mark_node); +} + +/* Parse a single source file. */ + +void +c_parse_file (void) +{ + /* Use local storage to begin. If the first token is a pragma, parse it. + If it is #pragma GCC pch_preprocess, then this will load a PCH file + which will cause garbage collection. */ + c_parser tparser; + + memset (&tparser, 0, sizeof tparser); + the_parser = &tparser; + + if (c_parser_peek_token (&tparser)->pragma_kind == PRAGMA_GCC_PCH_PREPROCESS) + c_parser_pragma_pch_preprocess (&tparser); + + the_parser = ggc_alloc_c_parser (); + *the_parser = tparser; + + /* Initialize EH, if we've been told to do so. */ + if (flag_exceptions) + using_eh_for_cleanups (); + + c_parser_translation_unit (the_parser); + the_parser = NULL; +} + +#include "gt-c-c-parser.h" diff --git a/gcc/c/c-tree.h b/gcc/c/c-tree.h new file mode 100644 index 00000000000..145df357af9 --- /dev/null +++ b/gcc/c/c-tree.h @@ -0,0 +1,676 @@ +/* Definitions for C parsing and type checking. + Copyright (C) 1987, 1993, 1994, 1995, 1997, 1998, + 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2007, 2008, 2009, 2010, 2011 + Free Software Foundation, Inc. + +This file is part of GCC. + +GCC 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 3, or (at your option) any later +version. + +GCC 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 GCC; see the file COPYING3. If not see +<http://www.gnu.org/licenses/>. */ + +#ifndef GCC_C_TREE_H +#define GCC_C_TREE_H + +#include "c-family/c-common.h" +#include "diagnostic.h" + +/* struct lang_identifier is private to c-decl.c, but langhooks.c needs to + know how big it is. This is sanity-checked in c-decl.c. */ +#define C_SIZEOF_STRUCT_LANG_IDENTIFIER \ + (sizeof (struct c_common_identifier) + 3 * sizeof (void *)) + +/* In a RECORD_TYPE or UNION_TYPE, nonzero if any component is read-only. */ +#define C_TYPE_FIELDS_READONLY(TYPE) TREE_LANG_FLAG_1 (TYPE) + +/* In a RECORD_TYPE or UNION_TYPE, nonzero if any component is volatile. */ +#define C_TYPE_FIELDS_VOLATILE(TYPE) TREE_LANG_FLAG_2 (TYPE) + +/* In a RECORD_TYPE or UNION_TYPE or ENUMERAL_TYPE + nonzero if the definition of the type has already started. */ +#define C_TYPE_BEING_DEFINED(TYPE) TYPE_LANG_FLAG_0 (TYPE) + +/* In an incomplete RECORD_TYPE or UNION_TYPE, a list of variable + declarations whose type would be completed by completing that type. */ +#define C_TYPE_INCOMPLETE_VARS(TYPE) TYPE_VFIELD (TYPE) + +/* In an IDENTIFIER_NODE, nonzero if this identifier is actually a + keyword. C_RID_CODE (node) is then the RID_* value of the keyword, + and C_RID_YYCODE is the token number wanted by Yacc. */ +#define C_IS_RESERVED_WORD(ID) TREE_LANG_FLAG_0 (ID) + +/* Record whether a type or decl was written with nonconstant size. + Note that TYPE_SIZE may have simplified to a constant. */ +#define C_TYPE_VARIABLE_SIZE(TYPE) TYPE_LANG_FLAG_1 (TYPE) +#define C_DECL_VARIABLE_SIZE(TYPE) DECL_LANG_FLAG_0 (TYPE) + +/* Record whether a type is defined inside a struct or union type. + This is used for -Wc++-compat. */ +#define C_TYPE_DEFINED_IN_STRUCT(TYPE) TYPE_LANG_FLAG_2 (TYPE) + +/* Record whether a typedef for type `int' was actually `signed int'. */ +#define C_TYPEDEF_EXPLICITLY_SIGNED(EXP) DECL_LANG_FLAG_1 (EXP) + +/* For a FUNCTION_DECL, nonzero if it was defined without an explicit + return type. */ +#define C_FUNCTION_IMPLICIT_INT(EXP) DECL_LANG_FLAG_1 (EXP) + +/* For a FUNCTION_DECL, nonzero if it was an implicit declaration. */ +#define C_DECL_IMPLICIT(EXP) DECL_LANG_FLAG_2 (EXP) + +/* For FUNCTION_DECLs, evaluates true if the decl is built-in but has + been declared. */ +#define C_DECL_DECLARED_BUILTIN(EXP) \ + DECL_LANG_FLAG_3 (FUNCTION_DECL_CHECK (EXP)) + +/* For FUNCTION_DECLs, evaluates true if the decl is built-in, has a + built-in prototype and does not have a non-built-in prototype. */ +#define C_DECL_BUILTIN_PROTOTYPE(EXP) \ + DECL_LANG_FLAG_6 (FUNCTION_DECL_CHECK (EXP)) + +/* Record whether a decl was declared register. This is strictly a + front-end flag, whereas DECL_REGISTER is used for code generation; + they may differ for structures with volatile fields. */ +#define C_DECL_REGISTER(EXP) DECL_LANG_FLAG_4 (EXP) + +/* Record whether a decl was used in an expression anywhere except an + unevaluated operand of sizeof / typeof / alignof. This is only + used for functions declared static but not defined, though outside + sizeof and typeof it is set for other function decls as well. */ +#define C_DECL_USED(EXP) DECL_LANG_FLAG_5 (FUNCTION_DECL_CHECK (EXP)) + +/* Record whether a variable has been declared threadprivate by + #pragma omp threadprivate. */ +#define C_DECL_THREADPRIVATE_P(DECL) DECL_LANG_FLAG_3 (VAR_DECL_CHECK (DECL)) + +/* Nonzero for a decl which either doesn't exist or isn't a prototype. + N.B. Could be simplified if all built-in decls had complete prototypes + (but this is presently difficult because some of them need FILE*). */ +#define C_DECL_ISNT_PROTOTYPE(EXP) \ + (EXP == 0 \ + || (!prototype_p (TREE_TYPE (EXP)) \ + && !DECL_BUILT_IN (EXP))) + +/* For FUNCTION_TYPE, a hidden list of types of arguments. The same as + TYPE_ARG_TYPES for functions with prototypes, but created for functions + without prototypes. */ +#define TYPE_ACTUAL_ARG_TYPES(NODE) TYPE_LANG_SLOT_1 (NODE) + +/* For a CONSTRUCTOR, whether some initializer contains a + subexpression meaning it is not a constant expression. */ +#define CONSTRUCTOR_NON_CONST(EXPR) TREE_LANG_FLAG_1 (CONSTRUCTOR_CHECK (EXPR)) + +/* Record parser information about an expression that is irrelevant + for code generation alongside a tree representing its value. */ +struct c_expr +{ + /* The value of the expression. */ + tree value; + /* Record the original unary/binary operator of an expression, which may + have been changed by fold, STRING_CST for unparenthesized string + constants, C_MAYBE_CONST_EXPR for __builtin_constant_p calls + (even if parenthesized), for subexpressions, and for non-constant + initializers, or ERROR_MARK for other expressions (including + parenthesized expressions). */ + enum tree_code original_code; + /* If not NULL, the original type of an expression. This will + differ from the type of the value field for an enum constant. + The type of an enum constant is a plain integer type, but this + field will be the enum type. */ + tree original_type; +}; + +/* Type alias for struct c_expr. This allows to use the structure + inside the VEC types. */ +typedef struct c_expr c_expr_t; + +/* A varray of c_expr_t. */ +DEF_VEC_O (c_expr_t); +DEF_VEC_ALLOC_O (c_expr_t, gc); +DEF_VEC_ALLOC_O (c_expr_t, heap); + +/* Append a new c_expr_t element to V. */ +#define C_EXPR_APPEND(V, ELEM) \ + do { \ + c_expr_t *__elem_p = VEC_safe_push (c_expr_t, gc, V, NULL); \ + *__elem_p = (ELEM); \ + } while (0) + +/* A kind of type specifier. Note that this information is currently + only used to distinguish tag definitions, tag references and typeof + uses. */ +enum c_typespec_kind { + /* No typespec. This appears only in struct c_declspec. */ + ctsk_none, + /* A reserved keyword type specifier. */ + ctsk_resword, + /* A reference to a tag, previously declared, such as "struct foo". + This includes where the previous declaration was as a different + kind of tag, in which case this is only valid if shadowing that + tag in an inner scope. */ + ctsk_tagref, + /* A reference to a tag, not previously declared in a visible + scope. */ + ctsk_tagfirstref, + /* A definition of a tag such as "struct foo { int a; }". */ + ctsk_tagdef, + /* A typedef name. */ + ctsk_typedef, + /* An ObjC-specific kind of type specifier. */ + ctsk_objc, + /* A typeof specifier. */ + ctsk_typeof +}; + +/* A type specifier: this structure is created in the parser and + passed to declspecs_add_type only. */ +struct c_typespec { + /* What kind of type specifier this is. */ + enum c_typespec_kind kind; + /* Whether the expression has operands suitable for use in constant + expressions. */ + bool expr_const_operands; + /* The specifier itself. */ + tree spec; + /* An expression to be evaluated before the type specifier, in the + case of typeof specifiers, or NULL otherwise or if no such + expression is required for a particular typeof specifier. In + particular, when typeof is applied to an expression of variably + modified type, that expression must be evaluated in order to + determine array sizes that form part of the type, but the + expression itself (as opposed to the array sizes) forms no part + of the type and so needs to be recorded separately. */ + tree expr; +}; + +/* A storage class specifier. */ +enum c_storage_class { + csc_none, + csc_auto, + csc_extern, + csc_register, + csc_static, + csc_typedef +}; + +/* A type specifier keyword "void", "_Bool", "char", "int", "float", + "double", "_Decimal32", "_Decimal64", "_Decimal128", "_Fract", "_Accum", + or none of these. */ +enum c_typespec_keyword { + cts_none, + cts_void, + cts_bool, + cts_char, + cts_int, + cts_float, + cts_int128, + cts_double, + cts_dfloat32, + cts_dfloat64, + cts_dfloat128, + cts_fract, + cts_accum +}; + +/* This enum lists all the possible declarator specifiers, storage + class or attribute that a user can write. There is at least one + enumerator per possible declarator specifier in the struct + c_declspecs below. + + It is used to index the array of declspec locations in struct + c_declspecs. */ +enum c_declspec_word { + cdw_typespec /* A catch-all for a typespec. */, + cdw_storage_class /* A catch-all for a storage class */, + cdw_attributes, + cdw_typedef, + cdw_explicit_signed, + cdw_deprecated, + cdw_default_int, + cdw_long, + cdw_long_long, + cdw_short, + cdw_signed, + cdw_unsigned, + cdw_complex, + cdw_inline, + cdw_noreturn, + cdw_thread, + cdw_const, + cdw_volatile, + cdw_restrict, + cdw_saturating, + cdw_alignas, + cdw_address_space, + cdw_number_of_elements /* This one must always be the last + enumerator. */ +}; + +/* A sequence of declaration specifiers in C. When a new declaration + specifier is added, please update the enum c_declspec_word above + accordingly. */ +struct c_declspecs { + source_location locations[cdw_number_of_elements]; + /* The type specified, if a single type specifier such as a struct, + union or enum specifier, typedef name or typeof specifies the + whole type, or NULL_TREE if none or a keyword such as "void" or + "char" is used. Does not include qualifiers. */ + tree type; + /* Any expression to be evaluated before the type, from a typeof + specifier. */ + tree expr; + /* The attributes from a typedef decl. */ + tree decl_attr; + /* When parsing, the attributes. Outside the parser, this will be + NULL; attributes (possibly from multiple lists) will be passed + separately. */ + tree attrs; + /* The base-2 log of the greatest alignment required by an _Alignas + specifier, in bytes, or -1 if no such specifiers with nonzero + alignment. */ + int align_log; + /* The storage class specifier, or csc_none if none. */ + enum c_storage_class storage_class; + /* Any type specifier keyword used such as "int", not reflecting + modifiers such as "short", or cts_none if none. */ + ENUM_BITFIELD (c_typespec_keyword) typespec_word : 8; + /* The kind of type specifier if one has been seen, ctsk_none + otherwise. */ + ENUM_BITFIELD (c_typespec_kind) typespec_kind : 3; + /* Whether any expressions in typeof specifiers may appear in + constant expressions. */ + BOOL_BITFIELD expr_const_operands : 1; + /* Whether any declaration specifiers have been seen at all. */ + BOOL_BITFIELD declspecs_seen_p : 1; + /* Whether something other than a storage class specifier or + attribute has been seen. This is used to warn for the + obsolescent usage of storage class specifiers other than at the + start of the list. (Doing this properly would require function + specifiers to be handled separately from storage class + specifiers.) */ + BOOL_BITFIELD non_sc_seen_p : 1; + /* Whether the type is specified by a typedef or typeof name. */ + BOOL_BITFIELD typedef_p : 1; + /* Whether the type is explicitly "signed" or specified by a typedef + whose type is explicitly "signed". */ + BOOL_BITFIELD explicit_signed_p : 1; + /* Whether the specifiers include a deprecated typedef. */ + BOOL_BITFIELD deprecated_p : 1; + /* Whether the type defaulted to "int" because there were no type + specifiers. */ + BOOL_BITFIELD default_int_p : 1; + /* Whether "long" was specified. */ + BOOL_BITFIELD long_p : 1; + /* Whether "long" was specified more than once. */ + BOOL_BITFIELD long_long_p : 1; + /* Whether "short" was specified. */ + BOOL_BITFIELD short_p : 1; + /* Whether "signed" was specified. */ + BOOL_BITFIELD signed_p : 1; + /* Whether "unsigned" was specified. */ + BOOL_BITFIELD unsigned_p : 1; + /* Whether "complex" was specified. */ + BOOL_BITFIELD complex_p : 1; + /* Whether "inline" was specified. */ + BOOL_BITFIELD inline_p : 1; + /* Whether "_Noreturn" was speciied. */ + BOOL_BITFIELD noreturn_p : 1; + /* Whether "__thread" was specified. */ + BOOL_BITFIELD thread_p : 1; + /* Whether "const" was specified. */ + BOOL_BITFIELD const_p : 1; + /* Whether "volatile" was specified. */ + BOOL_BITFIELD volatile_p : 1; + /* Whether "restrict" was specified. */ + BOOL_BITFIELD restrict_p : 1; + /* Whether "_Sat" was specified. */ + BOOL_BITFIELD saturating_p : 1; + /* Whether any alignment specifier (even with zero alignment) was + specified. */ + BOOL_BITFIELD alignas_p : 1; + /* The address space that the declaration belongs to. */ + addr_space_t address_space; +}; + +/* The various kinds of declarators in C. */ +enum c_declarator_kind { + /* An identifier. */ + cdk_id, + /* A function. */ + cdk_function, + /* An array. */ + cdk_array, + /* A pointer. */ + cdk_pointer, + /* Parenthesized declarator with nested attributes. */ + cdk_attrs +}; + +typedef struct c_arg_tag_d { + /* The argument name. */ + tree id; + /* The type of the argument. */ + tree type; +} c_arg_tag; + +DEF_VEC_O(c_arg_tag); +DEF_VEC_ALLOC_O(c_arg_tag,gc); + +/* Information about the parameters in a function declarator. */ +struct c_arg_info { + /* A list of parameter decls. */ + tree parms; + /* A list of structure, union and enum tags defined. */ + VEC(c_arg_tag,gc) *tags; + /* A list of argument types to go in the FUNCTION_TYPE. */ + tree types; + /* A list of non-parameter decls (notably enumeration constants) + defined with the parameters. */ + tree others; + /* A compound expression of VLA sizes from the parameters, or NULL. + In a function definition, these are used to ensure that + side-effects in sizes of arrays converted to pointers (such as a + parameter int i[n++]) take place; otherwise, they are + ignored. */ + tree pending_sizes; + /* True when these arguments had [*]. */ + BOOL_BITFIELD had_vla_unspec : 1; +}; + +/* A declarator. */ +struct c_declarator { + /* The kind of declarator. */ + enum c_declarator_kind kind; + location_t id_loc; /* Currently only set for cdk_id, cdk_array. */ + /* Except for cdk_id, the contained declarator. For cdk_id, NULL. */ + struct c_declarator *declarator; + union { + /* For identifiers, an IDENTIFIER_NODE or NULL_TREE if an abstract + declarator. */ + tree id; + /* For functions. */ + struct c_arg_info *arg_info; + /* For arrays. */ + struct { + /* The array dimension, or NULL for [] and [*]. */ + tree dimen; + /* The qualifiers inside []. */ + int quals; + /* The attributes (currently ignored) inside []. */ + tree attrs; + /* Whether [static] was used. */ + BOOL_BITFIELD static_p : 1; + /* Whether [*] was used. */ + BOOL_BITFIELD vla_unspec_p : 1; + } array; + /* For pointers, the qualifiers on the pointer type. */ + int pointer_quals; + /* For attributes. */ + tree attrs; + } u; +}; + +/* A type name. */ +struct c_type_name { + /* The declaration specifiers. */ + struct c_declspecs *specs; + /* The declarator. */ + struct c_declarator *declarator; +}; + +/* A parameter. */ +struct c_parm { + /* The declaration specifiers, minus any prefix attributes. */ + struct c_declspecs *specs; + /* The attributes. */ + tree attrs; + /* The declarator. */ + struct c_declarator *declarator; +}; + +/* Used when parsing an enum. Initialized by start_enum. */ +struct c_enum_contents +{ + /* While defining an enum type, this is 1 plus the last enumerator + constant value. */ + tree enum_next_value; + + /* Nonzero means that there was overflow computing enum_next_value. */ + int enum_overflow; +}; + +/* A type of reference to a static identifier in an inline + function. */ +enum c_inline_static_type { + /* Identifier with internal linkage used in function that may be an + inline definition (i.e., file-scope static). */ + csi_internal, + /* Modifiable object with static storage duration defined in + function that may be an inline definition (i.e., local + static). */ + csi_modifiable +}; + + +/* in c-parser.c */ +extern void c_parse_init (void); + +/* in c-aux-info.c */ +extern void gen_aux_info_record (tree, int, int, int); + +/* in c-decl.c */ +struct c_spot_bindings; +struct c_struct_parse_info; +extern struct obstack parser_obstack; +extern tree c_break_label; +extern tree c_cont_label; + +extern bool global_bindings_p (void); +extern void push_scope (void); +extern tree pop_scope (void); +extern void c_bindings_start_stmt_expr (struct c_spot_bindings *); +extern void c_bindings_end_stmt_expr (struct c_spot_bindings *); + +extern void record_inline_static (location_t, tree, tree, + enum c_inline_static_type); +extern void c_init_decl_processing (void); +extern void c_print_identifier (FILE *, tree, int); +extern int quals_from_declspecs (const struct c_declspecs *); +extern struct c_declarator *build_array_declarator (location_t, tree, + struct c_declspecs *, + bool, bool); +extern tree build_enumerator (location_t, location_t, struct c_enum_contents *, + tree, tree); +extern tree check_for_loop_decls (location_t, bool); +extern void mark_forward_parm_decls (void); +extern void declare_parm_level (void); +extern void undeclared_variable (location_t, tree); +extern tree lookup_label_for_goto (location_t, tree); +extern tree declare_label (tree); +extern tree define_label (location_t, tree); +extern struct c_spot_bindings *c_get_switch_bindings (void); +extern void c_release_switch_bindings (struct c_spot_bindings *); +extern bool c_check_switch_jump_warnings (struct c_spot_bindings *, + location_t, location_t); +extern void finish_decl (tree, location_t, tree, tree, tree); +extern tree finish_enum (tree, tree, tree); +extern void finish_function (void); +extern tree finish_struct (location_t, tree, tree, tree, + struct c_struct_parse_info *); +extern struct c_arg_info *build_arg_info (void); +extern struct c_arg_info *get_parm_info (bool, tree); +extern tree grokfield (location_t, struct c_declarator *, + struct c_declspecs *, tree, tree *); +extern tree groktypename (struct c_type_name *, tree *, bool *); +extern tree grokparm (const struct c_parm *, tree *); +extern tree implicitly_declare (location_t, tree); +extern void keep_next_level (void); +extern void pending_xref_error (void); +extern void c_push_function_context (void); +extern void c_pop_function_context (void); +extern void push_parm_decl (const struct c_parm *, tree *); +extern struct c_declarator *set_array_declarator_inner (struct c_declarator *, + struct c_declarator *); +extern tree c_builtin_function (tree); +extern tree c_builtin_function_ext_scope (tree); +extern void shadow_tag (const struct c_declspecs *); +extern void shadow_tag_warned (const struct c_declspecs *, int); +extern tree start_enum (location_t, struct c_enum_contents *, tree); +extern int start_function (struct c_declspecs *, struct c_declarator *, tree); +extern tree start_decl (struct c_declarator *, struct c_declspecs *, bool, + tree); +extern tree start_struct (location_t, enum tree_code, tree, + struct c_struct_parse_info **); +extern void store_parm_decls (void); +extern void store_parm_decls_from (struct c_arg_info *); +extern tree xref_tag (enum tree_code, tree); +extern struct c_typespec parser_xref_tag (location_t, enum tree_code, tree); +extern struct c_parm *build_c_parm (struct c_declspecs *, tree, + struct c_declarator *); +extern struct c_declarator *build_attrs_declarator (tree, + struct c_declarator *); +extern struct c_declarator *build_function_declarator (struct c_arg_info *, + struct c_declarator *); +extern struct c_declarator *build_id_declarator (tree); +extern struct c_declarator *make_pointer_declarator (struct c_declspecs *, + struct c_declarator *); +extern struct c_declspecs *build_null_declspecs (void); +extern struct c_declspecs *declspecs_add_qual (source_location, + struct c_declspecs *, tree); +extern struct c_declspecs *declspecs_add_type (location_t, + struct c_declspecs *, + struct c_typespec); +extern struct c_declspecs *declspecs_add_scspec (source_location, + struct c_declspecs *, tree); +extern struct c_declspecs *declspecs_add_attrs (source_location, + struct c_declspecs *, tree); +extern struct c_declspecs *declspecs_add_addrspace (source_location, + struct c_declspecs *, + addr_space_t); +extern struct c_declspecs *declspecs_add_alignas (source_location, + struct c_declspecs *, tree); +extern struct c_declspecs *finish_declspecs (struct c_declspecs *); + +/* in c-objc-common.c */ +extern bool c_objc_common_init (void); +extern bool c_missing_noreturn_ok_p (tree); +extern bool c_warn_unused_global_decl (const_tree); +extern void c_initialize_diagnostics (diagnostic_context *); +extern bool c_vla_unspec_p (tree x, tree fn); + +/* in c-typeck.c */ +extern int in_alignof; +extern int in_sizeof; +extern int in_typeof; + +extern struct c_switch *c_switch_stack; + +extern tree c_objc_common_truthvalue_conversion (location_t, tree); +extern tree require_complete_type (tree); +extern int same_translation_unit_p (const_tree, const_tree); +extern int comptypes (tree, tree); +extern int comptypes_check_different_types (tree, tree, bool *); +extern bool c_vla_type_p (const_tree); +extern bool c_mark_addressable (tree); +extern void c_incomplete_type_error (const_tree, const_tree); +extern tree c_type_promotes_to (tree); +extern struct c_expr default_function_array_conversion (location_t, + struct c_expr); +extern struct c_expr default_function_array_read_conversion (location_t, + struct c_expr); +extern void mark_exp_read (tree); +extern tree composite_type (tree, tree); +extern tree build_component_ref (location_t, tree, tree); +extern tree build_array_ref (location_t, tree, tree); +extern tree build_external_ref (location_t, tree, int, tree *); +extern void pop_maybe_used (bool); +extern struct c_expr c_expr_sizeof_expr (location_t, struct c_expr); +extern struct c_expr c_expr_sizeof_type (location_t, struct c_type_name *); +extern struct c_expr parser_build_unary_op (location_t, enum tree_code, + struct c_expr); +extern struct c_expr parser_build_binary_op (location_t, + enum tree_code, struct c_expr, + struct c_expr); +extern tree build_conditional_expr (location_t, tree, bool, tree, tree, + tree, tree); +extern tree build_compound_expr (location_t, tree, tree); +extern tree c_cast_expr (location_t, struct c_type_name *, tree); +extern tree build_c_cast (location_t, tree, tree); +extern void store_init_value (location_t, tree, tree, tree); +extern void error_init (const char *); +extern void pedwarn_init (location_t, int opt, const char *); +extern void maybe_warn_string_init (tree, struct c_expr); +extern void start_init (tree, tree, int); +extern void finish_init (void); +extern void really_start_incremental_init (tree); +extern void push_init_level (int, struct obstack *); +extern struct c_expr pop_init_level (int, struct obstack *); +extern void set_init_index (tree, tree, struct obstack *); +extern void set_init_label (tree, struct obstack *); +extern void process_init_element (struct c_expr, bool, struct obstack *); +extern tree build_compound_literal (location_t, tree, tree, bool); +extern void check_compound_literal_type (location_t, struct c_type_name *); +extern tree c_start_case (location_t, location_t, tree); +extern void c_finish_case (tree); +extern tree build_asm_expr (location_t, tree, tree, tree, tree, tree, bool); +extern tree build_asm_stmt (tree, tree); +extern int c_types_compatible_p (tree, tree); +extern tree c_begin_compound_stmt (bool); +extern tree c_end_compound_stmt (location_t, tree, bool); +extern void c_finish_if_stmt (location_t, tree, tree, tree, bool); +extern void c_finish_loop (location_t, tree, tree, tree, tree, tree, bool); +extern tree c_begin_stmt_expr (void); +extern tree c_finish_stmt_expr (location_t, tree); +extern tree c_process_expr_stmt (location_t, tree); +extern tree c_finish_expr_stmt (location_t, tree); +extern tree c_finish_return (location_t, tree, tree); +extern tree c_finish_bc_stmt (location_t, tree *, bool); +extern tree c_finish_goto_label (location_t, tree); +extern tree c_finish_goto_ptr (location_t, tree); +extern tree c_expr_to_decl (tree, bool *, bool *); +extern tree c_begin_omp_parallel (void); +extern tree c_finish_omp_parallel (location_t, tree, tree); +extern tree c_begin_omp_task (void); +extern tree c_finish_omp_task (location_t, tree, tree); +extern tree c_finish_omp_clauses (tree); +extern tree c_build_va_arg (location_t, tree, tree); +extern tree c_finish_transaction (location_t, tree, int); + +/* Set to 0 at beginning of a function definition, set to 1 if + a return statement that specifies a return value is seen. */ + +extern 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. */ + +extern int current_function_returns_null; + +/* Set to 0 at beginning of a function definition, set to 1 if + a call to a noreturn function is seen. */ + +extern int current_function_returns_abnormally; + +/* Mode used to build pointers (VOIDmode means ptr_mode). */ + +extern enum machine_mode c_default_pointer_mode; + +/* In c-decl.c */ +extern void c_finish_incomplete_decl (tree); +extern void c_write_global_declarations (void); + +/* In c-errors.c */ +extern void pedwarn_c90 (location_t, int opt, const char *, ...) ATTRIBUTE_GCC_DIAG(3,4); +extern void pedwarn_c99 (location_t, int opt, const char *, ...) ATTRIBUTE_GCC_DIAG(3,4); + +#endif /* ! GCC_C_TREE_H */ diff --git a/gcc/c/c-typeck.c b/gcc/c/c-typeck.c new file mode 100644 index 00000000000..c2f713eb02d --- /dev/null +++ b/gcc/c/c-typeck.c @@ -0,0 +1,10939 @@ +/* Build expressions with type checking for C compiler. + Copyright (C) 1987, 1988, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, + 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 + Free Software Foundation, Inc. + +This file is part of GCC. + +GCC 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 3, or (at your option) any later +version. + +GCC 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 GCC; see the file COPYING3. If not see +<http://www.gnu.org/licenses/>. */ + + +/* 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. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "tm.h" +#include "tree.h" +#include "langhooks.h" +#include "c-tree.h" +#include "c-lang.h" +#include "flags.h" +#include "intl.h" +#include "target.h" +#include "tree-iterator.h" +#include "bitmap.h" +#include "gimple.h" +#include "c-family/c-objc.h" + +/* Possible cases of implicit bad conversions. Used to select + diagnostic messages in convert_for_assignment. */ +enum impl_conv { + ic_argpass, + ic_assign, + ic_init, + ic_return +}; + +/* Possibe cases of scalar_to_vector conversion. */ +enum stv_conv { + stv_error, /* Error occured. */ + stv_nothing, /* Nothing happened. */ + stv_firstarg, /* First argument must be expanded. */ + stv_secondarg /* Second argument must be expanded. */ +}; + +/* The level of nesting inside "__alignof__". */ +int in_alignof; + +/* The level of nesting inside "sizeof". */ +int in_sizeof; + +/* The level of nesting inside "typeof". */ +int in_typeof; + +/* Nonzero if we've already printed a "missing braces around initializer" + message within this initializer. */ +static int missing_braces_mentioned; + +static int require_constant_value; +static int require_constant_elements; + +static bool null_pointer_constant_p (const_tree); +static tree qualify_type (tree, tree); +static int tagged_types_tu_compatible_p (const_tree, const_tree, bool *, + bool *); +static int comp_target_types (location_t, tree, tree); +static int function_types_compatible_p (const_tree, const_tree, bool *, + bool *); +static int type_lists_compatible_p (const_tree, const_tree, bool *, bool *); +static tree lookup_field (tree, tree); +static int convert_arguments (tree, VEC(tree,gc) *, VEC(tree,gc) *, tree, + tree); +static tree pointer_diff (location_t, tree, tree); +static tree convert_for_assignment (location_t, tree, tree, tree, + enum impl_conv, bool, tree, tree, int); +static tree valid_compound_expr_initializer (tree, tree); +static void push_string (const char *); +static void push_member_name (tree); +static int spelling_length (void); +static char *print_spelling (char *); +static void warning_init (int, const char *); +static tree digest_init (location_t, tree, tree, tree, bool, bool, int); +static void output_init_element (tree, tree, bool, tree, tree, int, bool, + struct obstack *); +static void output_pending_init_elements (int, struct obstack *); +static int set_designator (int, struct obstack *); +static void push_range_stack (tree, struct obstack *); +static void add_pending_init (tree, tree, tree, bool, struct obstack *); +static void set_nonincremental_init (struct obstack *); +static void set_nonincremental_init_from_string (tree, struct obstack *); +static tree find_init_member (tree, struct obstack *); +static void readonly_warning (tree, enum lvalue_use); +static int lvalue_or_else (location_t, const_tree, enum lvalue_use); +static void record_maybe_used_decl (tree); +static int comptypes_internal (const_tree, const_tree, bool *, bool *); + +/* Return true if EXP is a null pointer constant, false otherwise. */ + +static bool +null_pointer_constant_p (const_tree expr) +{ + /* This should really operate on c_expr structures, but they aren't + yet available everywhere required. */ + tree type = TREE_TYPE (expr); + return (TREE_CODE (expr) == INTEGER_CST + && !TREE_OVERFLOW (expr) + && integer_zerop (expr) + && (INTEGRAL_TYPE_P (type) + || (TREE_CODE (type) == POINTER_TYPE + && VOID_TYPE_P (TREE_TYPE (type)) + && TYPE_QUALS (TREE_TYPE (type)) == TYPE_UNQUALIFIED))); +} + +/* EXPR may appear in an unevaluated part of an integer constant + expression, but not in an evaluated part. Wrap it in a + C_MAYBE_CONST_EXPR, or mark it with TREE_OVERFLOW if it is just an + INTEGER_CST and we cannot create a C_MAYBE_CONST_EXPR. */ + +static tree +note_integer_operands (tree expr) +{ + tree ret; + if (TREE_CODE (expr) == INTEGER_CST && in_late_binary_op) + { + ret = copy_node (expr); + TREE_OVERFLOW (ret) = 1; + } + else + { + ret = build2 (C_MAYBE_CONST_EXPR, TREE_TYPE (expr), NULL_TREE, expr); + C_MAYBE_CONST_EXPR_INT_OPERANDS (ret) = 1; + } + return ret; +} + +/* Having checked whether EXPR may appear in an unevaluated part of an + integer constant expression and found that it may, remove any + C_MAYBE_CONST_EXPR noting this fact and return the resulting + expression. */ + +static inline tree +remove_c_maybe_const_expr (tree expr) +{ + if (TREE_CODE (expr) == C_MAYBE_CONST_EXPR) + return C_MAYBE_CONST_EXPR_EXPR (expr); + else + return expr; +} + +/* This is a cache to hold if two types are compatible or not. */ + +struct tagged_tu_seen_cache { + const struct tagged_tu_seen_cache * next; + const_tree t1; + const_tree t2; + /* The return value of tagged_types_tu_compatible_p if we had seen + these two types already. */ + int val; +}; + +static const struct tagged_tu_seen_cache * tagged_tu_seen_base; +static void free_all_tagged_tu_seen_up_to (const struct tagged_tu_seen_cache *); + +/* Do `exp = require_complete_type (exp);' to make sure exp + does not have an incomplete type. (That includes void types.) */ + +tree +require_complete_type (tree value) +{ + tree type = TREE_TYPE (value); + + if (value == error_mark_node || type == error_mark_node) + return error_mark_node; + + /* First, detect a valid value with a complete type. */ + if (COMPLETE_TYPE_P (type)) + return value; + + c_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. */ + +void +c_incomplete_type_error (const_tree value, const_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 ("%qD has an incomplete type", 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)) + { + if (TYPE_MAX_VALUE (TYPE_DOMAIN (type)) == NULL) + { + error ("invalid use of flexible array member"); + return; + } + type = TREE_TYPE (type); + goto retry; + } + error ("invalid use of array with unspecified bounds"); + return; + + default: + gcc_unreachable (); + } + + if (TREE_CODE (TYPE_NAME (type)) == IDENTIFIER_NODE) + error ("invalid use of undefined type %<%s %E%>", + type_code_string, TYPE_NAME (type)); + else + /* If this type has a typedef-name, the TYPE_NAME is a TYPE_DECL. */ + error ("invalid use of incomplete typedef %qD", TYPE_NAME (type)); + } +} + +/* Given a type, apply default promotions wrt unnamed function + arguments and return the new type. */ + +tree +c_type_promotes_to (tree type) +{ + if (TYPE_MAIN_VARIANT (type) == float_type_node) + return double_type_node; + + if (c_promoting_integer_type_p (type)) + { + /* Preserve unsignedness if not really getting any wider. */ + if (TYPE_UNSIGNED (type) + && (TYPE_PRECISION (type) == TYPE_PRECISION (integer_type_node))) + return unsigned_type_node; + return integer_type_node; + } + + return type; +} + +/* Return true if between two named address spaces, whether there is a superset + named address space that encompasses both address spaces. If there is a + superset, return which address space is the superset. */ + +static bool +addr_space_superset (addr_space_t as1, addr_space_t as2, addr_space_t *common) +{ + if (as1 == as2) + { + *common = as1; + return true; + } + else if (targetm.addr_space.subset_p (as1, as2)) + { + *common = as2; + return true; + } + else if (targetm.addr_space.subset_p (as2, as1)) + { + *common = as1; + return true; + } + else + return false; +} + +/* Return a variant of TYPE which has all the type qualifiers of LIKE + as well as those of TYPE. */ + +static tree +qualify_type (tree type, tree like) +{ + addr_space_t as_type = TYPE_ADDR_SPACE (type); + addr_space_t as_like = TYPE_ADDR_SPACE (like); + addr_space_t as_common; + + /* If the two named address spaces are different, determine the common + superset address space. If there isn't one, raise an error. */ + if (!addr_space_superset (as_type, as_like, &as_common)) + { + as_common = as_type; + error ("%qT and %qT are in disjoint named address spaces", + type, like); + } + + return c_build_qualified_type (type, + TYPE_QUALS_NO_ADDR_SPACE (type) + | TYPE_QUALS_NO_ADDR_SPACE (like) + | ENCODE_QUAL_ADDR_SPACE (as_common)); +} + +/* Return true iff the given tree T is a variable length array. */ + +bool +c_vla_type_p (const_tree t) +{ + if (TREE_CODE (t) == ARRAY_TYPE + && C_TYPE_VARIABLE_SIZE (t)) + return true; + return false; +} + +/* Return the composite type of two compatible types. + + We assume that comptypes has already been done and returned + nonzero; if that isn't so, this may crash. In particular, we + assume that qualifiers match. */ + +tree +composite_type (tree t1, tree t2) +{ + enum tree_code code1; + 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; + + code1 = TREE_CODE (t1); + code2 = TREE_CODE (t2); + + /* Merge the attributes. */ + attributes = targetm.merge_type_attributes (t1, t2); + + /* If one is an enumerated type and the other is the compatible + integer type, the composite type might be either of the two + (DR#013 question 3). For consistency, use the enumerated type as + the composite type. */ + + if (code1 == ENUMERAL_TYPE && code2 == INTEGER_TYPE) + return t1; + if (code2 == ENUMERAL_TYPE && code1 == INTEGER_TYPE) + return t2; + + gcc_assert (code1 == code2); + + switch (code1) + { + case POINTER_TYPE: + /* For two pointers, do this recursively on the target type. */ + { + tree pointed_to_1 = TREE_TYPE (t1); + tree pointed_to_2 = TREE_TYPE (t2); + tree target = composite_type (pointed_to_1, pointed_to_2); + t1 = build_pointer_type_for_mode (target, TYPE_MODE (t1), false); + t1 = build_type_attribute_variant (t1, attributes); + return qualify_type (t1, t2); + } + + case ARRAY_TYPE: + { + tree elt = composite_type (TREE_TYPE (t1), TREE_TYPE (t2)); + int quals; + tree unqual_elt; + tree d1 = TYPE_DOMAIN (t1); + tree d2 = TYPE_DOMAIN (t2); + bool d1_variable, d2_variable; + bool d1_zero, d2_zero; + bool t1_complete, t2_complete; + + /* We should not have any type quals on arrays at all. */ + gcc_assert (!TYPE_QUALS_NO_ADDR_SPACE (t1) + && !TYPE_QUALS_NO_ADDR_SPACE (t2)); + + t1_complete = COMPLETE_TYPE_P (t1); + t2_complete = COMPLETE_TYPE_P (t2); + + d1_zero = d1 == 0 || !TYPE_MAX_VALUE (d1); + d2_zero = d2 == 0 || !TYPE_MAX_VALUE (d2); + + d1_variable = (!d1_zero + && (TREE_CODE (TYPE_MIN_VALUE (d1)) != INTEGER_CST + || TREE_CODE (TYPE_MAX_VALUE (d1)) != INTEGER_CST)); + d2_variable = (!d2_zero + && (TREE_CODE (TYPE_MIN_VALUE (d2)) != INTEGER_CST + || TREE_CODE (TYPE_MAX_VALUE (d2)) != INTEGER_CST)); + d1_variable = d1_variable || (d1_zero && c_vla_type_p (t1)); + d2_variable = d2_variable || (d2_zero && c_vla_type_p (t2)); + + /* Save space: see if the result is identical to one of the args. */ + if (elt == TREE_TYPE (t1) && TYPE_DOMAIN (t1) + && (d2_variable || d2_zero || !d1_variable)) + return build_type_attribute_variant (t1, attributes); + if (elt == TREE_TYPE (t2) && TYPE_DOMAIN (t2) + && (d1_variable || d1_zero || !d2_variable)) + return build_type_attribute_variant (t2, attributes); + + if (elt == TREE_TYPE (t1) && !TYPE_DOMAIN (t2) && !TYPE_DOMAIN (t1)) + return build_type_attribute_variant (t1, attributes); + if (elt == TREE_TYPE (t2) && !TYPE_DOMAIN (t2) && !TYPE_DOMAIN (t1)) + return build_type_attribute_variant (t2, attributes); + + /* Merge the element types, and have a size if either arg has + one. We may have qualifiers on the element types. To set + up TYPE_MAIN_VARIANT correctly, we need to form the + composite of the unqualified types and add the qualifiers + back at the end. */ + quals = TYPE_QUALS (strip_array_types (elt)); + unqual_elt = c_build_qualified_type (elt, TYPE_UNQUALIFIED); + t1 = build_array_type (unqual_elt, + TYPE_DOMAIN ((TYPE_DOMAIN (t1) + && (d2_variable + || d2_zero + || !d1_variable)) + ? t1 + : t2)); + /* Ensure a composite type involving a zero-length array type + is a zero-length type not an incomplete type. */ + if (d1_zero && d2_zero + && (t1_complete || t2_complete) + && !COMPLETE_TYPE_P (t1)) + { + TYPE_SIZE (t1) = bitsize_zero_node; + TYPE_SIZE_UNIT (t1) = size_zero_node; + } + t1 = c_build_qualified_type (t1, quals); + return build_type_attribute_variant (t1, attributes); + } + + case ENUMERAL_TYPE: + case RECORD_TYPE: + case UNION_TYPE: + if (attributes != NULL) + { + /* Try harder not to create a new aggregate type. */ + if (attribute_list_equal (TYPE_ATTRIBUTES (t1), attributes)) + return t1; + if (attribute_list_equal (TYPE_ATTRIBUTES (t2), attributes)) + return 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 = composite_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)); + t1 = build_type_attribute_variant (t1, attributes); + return qualify_type (t1, t2); + } + if (TYPE_ARG_TYPES (t2) == 0) + { + t1 = build_function_type (valtype, TYPE_ARG_TYPES (t1)); + t1 = build_type_attribute_variant (t1, attributes); + return qualify_type (t1, t2); + } + + /* 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; + tree mv2 = TREE_VALUE (p2); + if (mv2 && mv2 != error_mark_node + && TREE_CODE (mv2) != ARRAY_TYPE) + mv2 = TYPE_MAIN_VARIANT (mv2); + for (memb = TYPE_FIELDS (TREE_VALUE (p1)); + memb; memb = DECL_CHAIN (memb)) + { + tree mv3 = TREE_TYPE (memb); + if (mv3 && mv3 != error_mark_node + && TREE_CODE (mv3) != ARRAY_TYPE) + mv3 = TYPE_MAIN_VARIANT (mv3); + if (comptypes (mv3, mv2)) + { + TREE_VALUE (n) = composite_type (TREE_TYPE (memb), + TREE_VALUE (p2)); + pedwarn (input_location, OPT_Wpedantic, + "function types not truly compatible in ISO C"); + goto parm_done; + } + } + } + if (TREE_CODE (TREE_VALUE (p2)) == UNION_TYPE + && TREE_VALUE (p2) != TREE_VALUE (p1)) + { + tree memb; + tree mv1 = TREE_VALUE (p1); + if (mv1 && mv1 != error_mark_node + && TREE_CODE (mv1) != ARRAY_TYPE) + mv1 = TYPE_MAIN_VARIANT (mv1); + for (memb = TYPE_FIELDS (TREE_VALUE (p2)); + memb; memb = DECL_CHAIN (memb)) + { + tree mv3 = TREE_TYPE (memb); + if (mv3 && mv3 != error_mark_node + && TREE_CODE (mv3) != ARRAY_TYPE) + mv3 = TYPE_MAIN_VARIANT (mv3); + if (comptypes (mv3, mv1)) + { + TREE_VALUE (n) = composite_type (TREE_TYPE (memb), + TREE_VALUE (p1)); + pedwarn (input_location, OPT_Wpedantic, + "function types not truly compatible in ISO C"); + goto parm_done; + } + } + } + TREE_VALUE (n) = composite_type (TREE_VALUE (p1), TREE_VALUE (p2)); + parm_done: ; + } + + t1 = build_function_type (valtype, newargs); + t1 = qualify_type (t1, t2); + /* ... falls through ... */ + } + + default: + return build_type_attribute_variant (t1, attributes); + } + +} + +/* Return the type of a conditional expression between pointers to + possibly differently qualified versions of compatible types. + + We assume that comp_target_types has already been done and returned + nonzero; if that isn't so, this may crash. */ + +static tree +common_pointer_type (tree t1, tree t2) +{ + tree attributes; + tree pointed_to_1, mv1; + tree pointed_to_2, mv2; + tree target; + unsigned target_quals; + addr_space_t as1, as2, as_common; + int quals1, quals2; + + /* 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; + + gcc_assert (TREE_CODE (t1) == POINTER_TYPE + && TREE_CODE (t2) == POINTER_TYPE); + + /* Merge the attributes. */ + attributes = targetm.merge_type_attributes (t1, t2); + + /* Find the composite type of the target types, and combine the + qualifiers of the two types' targets. Do not lose qualifiers on + array element types by taking the TYPE_MAIN_VARIANT. */ + mv1 = pointed_to_1 = TREE_TYPE (t1); + mv2 = pointed_to_2 = TREE_TYPE (t2); + if (TREE_CODE (mv1) != ARRAY_TYPE) + mv1 = TYPE_MAIN_VARIANT (pointed_to_1); + if (TREE_CODE (mv2) != ARRAY_TYPE) + mv2 = TYPE_MAIN_VARIANT (pointed_to_2); + target = composite_type (mv1, mv2); + + /* For function types do not merge const qualifiers, but drop them + if used inconsistently. The middle-end uses these to mark const + and noreturn functions. */ + quals1 = TYPE_QUALS_NO_ADDR_SPACE (pointed_to_1); + quals2 = TYPE_QUALS_NO_ADDR_SPACE (pointed_to_2); + + if (TREE_CODE (pointed_to_1) == FUNCTION_TYPE) + target_quals = (quals1 & quals2); + else + target_quals = (quals1 | quals2); + + /* If the two named address spaces are different, determine the common + superset address space. This is guaranteed to exist due to the + assumption that comp_target_type returned non-zero. */ + as1 = TYPE_ADDR_SPACE (pointed_to_1); + as2 = TYPE_ADDR_SPACE (pointed_to_2); + if (!addr_space_superset (as1, as2, &as_common)) + gcc_unreachable (); + + target_quals |= ENCODE_QUAL_ADDR_SPACE (as_common); + + t1 = build_pointer_type (c_build_qualified_type (target, target_quals)); + return build_type_attribute_variant (t1, attributes); +} + +/* Return the common type for two arithmetic types under the usual + arithmetic conversions. The default conversions have already been + applied, and enumerated types converted to their compatible integer + types. The resulting type is unqualified and has no attributes. + + This is the type for the result of most arithmetic operations + if the operands have the given two types. */ + +static tree +c_common_type (tree t1, tree t2) +{ + enum tree_code code1; + enum tree_code code2; + + /* If one type is nonsense, use the other. */ + if (t1 == error_mark_node) + return t2; + if (t2 == error_mark_node) + return t1; + + if (TYPE_QUALS (t1) != TYPE_UNQUALIFIED) + t1 = TYPE_MAIN_VARIANT (t1); + + if (TYPE_QUALS (t2) != TYPE_UNQUALIFIED) + t2 = TYPE_MAIN_VARIANT (t2); + + if (TYPE_ATTRIBUTES (t1) != NULL_TREE) + t1 = build_type_attribute_variant (t1, NULL_TREE); + + if (TYPE_ATTRIBUTES (t2) != NULL_TREE) + t2 = build_type_attribute_variant (t2, NULL_TREE); + + /* Save time if the two types are the same. */ + + if (t1 == t2) return t1; + + code1 = TREE_CODE (t1); + code2 = TREE_CODE (t2); + + gcc_assert (code1 == VECTOR_TYPE || code1 == COMPLEX_TYPE + || code1 == FIXED_POINT_TYPE || code1 == REAL_TYPE + || code1 == INTEGER_TYPE); + gcc_assert (code2 == VECTOR_TYPE || code2 == COMPLEX_TYPE + || code2 == FIXED_POINT_TYPE || code2 == REAL_TYPE + || code2 == INTEGER_TYPE); + + /* When one operand is a decimal float type, the other operand cannot be + a generic float type or a complex type. We also disallow vector types + here. */ + if ((DECIMAL_FLOAT_TYPE_P (t1) || DECIMAL_FLOAT_TYPE_P (t2)) + && !(DECIMAL_FLOAT_TYPE_P (t1) && DECIMAL_FLOAT_TYPE_P (t2))) + { + if (code1 == VECTOR_TYPE || code2 == VECTOR_TYPE) + { + error ("can%'t mix operands of decimal float and vector types"); + return error_mark_node; + } + if (code1 == COMPLEX_TYPE || code2 == COMPLEX_TYPE) + { + error ("can%'t mix operands of decimal float and complex types"); + return error_mark_node; + } + if (code1 == REAL_TYPE && code2 == REAL_TYPE) + { + error ("can%'t mix operands of decimal float and other float types"); + return error_mark_node; + } + } + + /* If one type is a vector type, return that type. (How the usual + arithmetic conversions apply to the vector types extension is not + precisely specified.) */ + if (code1 == VECTOR_TYPE) + return t1; + + if (code2 == VECTOR_TYPE) + return 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 = c_common_type (subtype1, subtype2); + + if (code1 == COMPLEX_TYPE && TREE_TYPE (t1) == subtype) + return t1; + else if (code2 == COMPLEX_TYPE && TREE_TYPE (t2) == subtype) + return t2; + else + return build_complex_type (subtype); + } + + /* If only one is real, use it as the result. */ + + if (code1 == REAL_TYPE && code2 != REAL_TYPE) + return t1; + + if (code2 == REAL_TYPE && code1 != REAL_TYPE) + return t2; + + /* If both are real and either are decimal floating point types, use + the decimal floating point type with the greater precision. */ + + if (code1 == REAL_TYPE && code2 == REAL_TYPE) + { + if (TYPE_MAIN_VARIANT (t1) == dfloat128_type_node + || TYPE_MAIN_VARIANT (t2) == dfloat128_type_node) + return dfloat128_type_node; + else if (TYPE_MAIN_VARIANT (t1) == dfloat64_type_node + || TYPE_MAIN_VARIANT (t2) == dfloat64_type_node) + return dfloat64_type_node; + else if (TYPE_MAIN_VARIANT (t1) == dfloat32_type_node + || TYPE_MAIN_VARIANT (t2) == dfloat32_type_node) + return dfloat32_type_node; + } + + /* Deal with fixed-point types. */ + if (code1 == FIXED_POINT_TYPE || code2 == FIXED_POINT_TYPE) + { + unsigned int unsignedp = 0, satp = 0; + enum machine_mode m1, m2; + unsigned int fbit1, ibit1, fbit2, ibit2, max_fbit, max_ibit; + + m1 = TYPE_MODE (t1); + m2 = TYPE_MODE (t2); + + /* If one input type is saturating, the result type is saturating. */ + if (TYPE_SATURATING (t1) || TYPE_SATURATING (t2)) + satp = 1; + + /* If both fixed-point types are unsigned, the result type is unsigned. + When mixing fixed-point and integer types, follow the sign of the + fixed-point type. + Otherwise, the result type is signed. */ + if ((TYPE_UNSIGNED (t1) && TYPE_UNSIGNED (t2) + && code1 == FIXED_POINT_TYPE && code2 == FIXED_POINT_TYPE) + || (code1 == FIXED_POINT_TYPE && code2 != FIXED_POINT_TYPE + && TYPE_UNSIGNED (t1)) + || (code1 != FIXED_POINT_TYPE && code2 == FIXED_POINT_TYPE + && TYPE_UNSIGNED (t2))) + unsignedp = 1; + + /* The result type is signed. */ + if (unsignedp == 0) + { + /* If the input type is unsigned, we need to convert to the + signed type. */ + if (code1 == FIXED_POINT_TYPE && TYPE_UNSIGNED (t1)) + { + enum mode_class mclass = (enum mode_class) 0; + if (GET_MODE_CLASS (m1) == MODE_UFRACT) + mclass = MODE_FRACT; + else if (GET_MODE_CLASS (m1) == MODE_UACCUM) + mclass = MODE_ACCUM; + else + gcc_unreachable (); + m1 = mode_for_size (GET_MODE_PRECISION (m1), mclass, 0); + } + if (code2 == FIXED_POINT_TYPE && TYPE_UNSIGNED (t2)) + { + enum mode_class mclass = (enum mode_class) 0; + if (GET_MODE_CLASS (m2) == MODE_UFRACT) + mclass = MODE_FRACT; + else if (GET_MODE_CLASS (m2) == MODE_UACCUM) + mclass = MODE_ACCUM; + else + gcc_unreachable (); + m2 = mode_for_size (GET_MODE_PRECISION (m2), mclass, 0); + } + } + + if (code1 == FIXED_POINT_TYPE) + { + fbit1 = GET_MODE_FBIT (m1); + ibit1 = GET_MODE_IBIT (m1); + } + else + { + fbit1 = 0; + /* Signed integers need to subtract one sign bit. */ + ibit1 = TYPE_PRECISION (t1) - (!TYPE_UNSIGNED (t1)); + } + + if (code2 == FIXED_POINT_TYPE) + { + fbit2 = GET_MODE_FBIT (m2); + ibit2 = GET_MODE_IBIT (m2); + } + else + { + fbit2 = 0; + /* Signed integers need to subtract one sign bit. */ + ibit2 = TYPE_PRECISION (t2) - (!TYPE_UNSIGNED (t2)); + } + + max_ibit = ibit1 >= ibit2 ? ibit1 : ibit2; + max_fbit = fbit1 >= fbit2 ? fbit1 : fbit2; + return c_common_fixed_point_type_for_size (max_ibit, max_fbit, unsignedp, + satp); + } + + /* Both real or both integers; use the one with greater precision. */ + + if (TYPE_PRECISION (t1) > TYPE_PRECISION (t2)) + return t1; + else if (TYPE_PRECISION (t2) > TYPE_PRECISION (t1)) + return t2; + + /* Same precision. Prefer long longs to longs to ints when the + same precision, following the C99 rules on integer type rank + (which are equivalent to the C90 rules for C90 types). */ + + if (TYPE_MAIN_VARIANT (t1) == long_long_unsigned_type_node + || TYPE_MAIN_VARIANT (t2) == long_long_unsigned_type_node) + return long_long_unsigned_type_node; + + if (TYPE_MAIN_VARIANT (t1) == long_long_integer_type_node + || TYPE_MAIN_VARIANT (t2) == long_long_integer_type_node) + { + if (TYPE_UNSIGNED (t1) || TYPE_UNSIGNED (t2)) + return long_long_unsigned_type_node; + else + return long_long_integer_type_node; + } + + if (TYPE_MAIN_VARIANT (t1) == long_unsigned_type_node + || TYPE_MAIN_VARIANT (t2) == long_unsigned_type_node) + return long_unsigned_type_node; + + 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 (TYPE_UNSIGNED (t1) || TYPE_UNSIGNED (t2)) + return long_unsigned_type_node; + else + return long_integer_type_node; + } + + /* 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 long_double_type_node; + + /* Otherwise prefer the unsigned one. */ + + if (TYPE_UNSIGNED (t1)) + return t1; + else + return t2; +} + +/* Wrapper around c_common_type that is used by c-common.c and other + front end optimizations that remove promotions. ENUMERAL_TYPEs + are allowed here and are converted to their compatible integer types. + BOOLEAN_TYPEs are allowed here and return either boolean_type_node or + preferably a non-Boolean type as the common type. */ +tree +common_type (tree t1, tree t2) +{ + if (TREE_CODE (t1) == ENUMERAL_TYPE) + t1 = c_common_type_for_size (TYPE_PRECISION (t1), 1); + if (TREE_CODE (t2) == ENUMERAL_TYPE) + t2 = c_common_type_for_size (TYPE_PRECISION (t2), 1); + + /* If both types are BOOLEAN_TYPE, then return boolean_type_node. */ + if (TREE_CODE (t1) == BOOLEAN_TYPE + && TREE_CODE (t2) == BOOLEAN_TYPE) + return boolean_type_node; + + /* If either type is BOOLEAN_TYPE, then return the other. */ + if (TREE_CODE (t1) == BOOLEAN_TYPE) + return t2; + if (TREE_CODE (t2) == BOOLEAN_TYPE) + return t1; + + return c_common_type (t1, t2); +} + +/* 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 (tree type1, tree type2) +{ + const struct tagged_tu_seen_cache * tagged_tu_seen_base1 = tagged_tu_seen_base; + int val; + + val = comptypes_internal (type1, type2, NULL, NULL); + free_all_tagged_tu_seen_up_to (tagged_tu_seen_base1); + + return val; +} + +/* Like comptypes, but if it returns non-zero because enum and int are + compatible, it sets *ENUM_AND_INT_P to true. */ + +static int +comptypes_check_enum_int (tree type1, tree type2, bool *enum_and_int_p) +{ + const struct tagged_tu_seen_cache * tagged_tu_seen_base1 = tagged_tu_seen_base; + int val; + + val = comptypes_internal (type1, type2, enum_and_int_p, NULL); + free_all_tagged_tu_seen_up_to (tagged_tu_seen_base1); + + return val; +} + +/* Like comptypes, but if it returns nonzero for different types, it + sets *DIFFERENT_TYPES_P to true. */ + +int +comptypes_check_different_types (tree type1, tree type2, + bool *different_types_p) +{ + const struct tagged_tu_seen_cache * tagged_tu_seen_base1 = tagged_tu_seen_base; + int val; + + val = comptypes_internal (type1, type2, NULL, different_types_p); + free_all_tagged_tu_seen_up_to (tagged_tu_seen_base1); + + return val; +} + +/* 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. If + ENUM_AND_INT_P is not NULL, and one type is an enum and the other a + compatible integer type, then this sets *ENUM_AND_INT_P to true; + *ENUM_AND_INT_P is never set to false. If DIFFERENT_TYPES_P is not + NULL, and the types are compatible but different enough not to be + permitted in C11 typedef redeclarations, then this sets + *DIFFERENT_TYPES_P to true; *DIFFERENT_TYPES_P is never set to + false, but may or may not be set if the types are incompatible. + This differs from comptypes, in that we don't free the seen + types. */ + +static int +comptypes_internal (const_tree type1, const_tree type2, bool *enum_and_int_p, + bool *different_types_p) +{ + const_tree t1 = type1; + const_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; + + /* Enumerated types are compatible with integer types, but this is + not transitive: two enumerated types in the same translation unit + are compatible with each other only if they are the same type. */ + + if (TREE_CODE (t1) == ENUMERAL_TYPE && TREE_CODE (t2) != ENUMERAL_TYPE) + { + t1 = c_common_type_for_size (TYPE_PRECISION (t1), TYPE_UNSIGNED (t1)); + if (TREE_CODE (t2) != VOID_TYPE) + { + if (enum_and_int_p != NULL) + *enum_and_int_p = true; + if (different_types_p != NULL) + *different_types_p = true; + } + } + else if (TREE_CODE (t2) == ENUMERAL_TYPE && TREE_CODE (t1) != ENUMERAL_TYPE) + { + t2 = c_common_type_for_size (TYPE_PRECISION (t2), TYPE_UNSIGNED (t2)); + if (TREE_CODE (t1) != VOID_TYPE) + { + if (enum_and_int_p != NULL) + *enum_and_int_p = true; + if (different_types_p != NULL) + *different_types_p = true; + } + } + + 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. C99 6.7.3p9 */ + + 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 (TREE_CODE (t1) != ARRAY_TYPE + && TYPE_MAIN_VARIANT (t1) == TYPE_MAIN_VARIANT (t2)) + return 1; + + /* 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: + /* Do not remove mode or aliasing information. */ + if (TYPE_MODE (t1) != TYPE_MODE (t2) + || TYPE_REF_CAN_ALIAS_ALL (t1) != TYPE_REF_CAN_ALIAS_ALL (t2)) + break; + val = (TREE_TYPE (t1) == TREE_TYPE (t2) + ? 1 : comptypes_internal (TREE_TYPE (t1), TREE_TYPE (t2), + enum_and_int_p, different_types_p)); + break; + + case FUNCTION_TYPE: + val = function_types_compatible_p (t1, t2, enum_and_int_p, + different_types_p); + break; + + case ARRAY_TYPE: + { + tree d1 = TYPE_DOMAIN (t1); + tree d2 = TYPE_DOMAIN (t2); + bool d1_variable, d2_variable; + bool d1_zero, d2_zero; + val = 1; + + /* Target types must match incl. qualifiers. */ + if (TREE_TYPE (t1) != TREE_TYPE (t2) + && 0 == (val = comptypes_internal (TREE_TYPE (t1), TREE_TYPE (t2), + enum_and_int_p, + different_types_p))) + return 0; + + if (different_types_p != NULL + && (d1 == 0) != (d2 == 0)) + *different_types_p = true; + /* Sizes must match unless one is missing or variable. */ + if (d1 == 0 || d2 == 0 || d1 == d2) + break; + + d1_zero = !TYPE_MAX_VALUE (d1); + d2_zero = !TYPE_MAX_VALUE (d2); + + d1_variable = (!d1_zero + && (TREE_CODE (TYPE_MIN_VALUE (d1)) != INTEGER_CST + || TREE_CODE (TYPE_MAX_VALUE (d1)) != INTEGER_CST)); + d2_variable = (!d2_zero + && (TREE_CODE (TYPE_MIN_VALUE (d2)) != INTEGER_CST + || TREE_CODE (TYPE_MAX_VALUE (d2)) != INTEGER_CST)); + d1_variable = d1_variable || (d1_zero && c_vla_type_p (t1)); + d2_variable = d2_variable || (d2_zero && c_vla_type_p (t2)); + + if (different_types_p != NULL + && d1_variable != d2_variable) + *different_types_p = true; + if (d1_variable || d2_variable) + break; + if (d1_zero && d2_zero) + break; + if (d1_zero || d2_zero + || !tree_int_cst_equal (TYPE_MIN_VALUE (d1), TYPE_MIN_VALUE (d2)) + || !tree_int_cst_equal (TYPE_MAX_VALUE (d1), TYPE_MAX_VALUE (d2))) + val = 0; + + break; + } + + case ENUMERAL_TYPE: + case RECORD_TYPE: + case UNION_TYPE: + if (val != 1 && !same_translation_unit_p (t1, t2)) + { + tree a1 = TYPE_ATTRIBUTES (t1); + tree a2 = TYPE_ATTRIBUTES (t2); + + if (! attribute_list_contained (a1, a2) + && ! attribute_list_contained (a2, a1)) + break; + + if (attrval != 2) + return tagged_types_tu_compatible_p (t1, t2, enum_and_int_p, + different_types_p); + val = tagged_types_tu_compatible_p (t1, t2, enum_and_int_p, + different_types_p); + } + break; + + case VECTOR_TYPE: + val = (TYPE_VECTOR_SUBPARTS (t1) == TYPE_VECTOR_SUBPARTS (t2) + && comptypes_internal (TREE_TYPE (t1), TREE_TYPE (t2), + enum_and_int_p, different_types_p)); + 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, except for named address spaces. If the pointers point to + different named addresses, then we must determine if one address space is a + subset of the other. */ + +static int +comp_target_types (location_t location, tree ttl, tree ttr) +{ + int val; + tree mvl = TREE_TYPE (ttl); + tree mvr = TREE_TYPE (ttr); + addr_space_t asl = TYPE_ADDR_SPACE (mvl); + addr_space_t asr = TYPE_ADDR_SPACE (mvr); + addr_space_t as_common; + bool enum_and_int_p; + + /* Fail if pointers point to incompatible address spaces. */ + if (!addr_space_superset (asl, asr, &as_common)) + return 0; + + /* Do not lose qualifiers on element types of array types that are + pointer targets by taking their TYPE_MAIN_VARIANT. */ + if (TREE_CODE (mvl) != ARRAY_TYPE) + mvl = TYPE_MAIN_VARIANT (mvl); + if (TREE_CODE (mvr) != ARRAY_TYPE) + mvr = TYPE_MAIN_VARIANT (mvr); + enum_and_int_p = false; + val = comptypes_check_enum_int (mvl, mvr, &enum_and_int_p); + + if (val == 2) + pedwarn (location, OPT_Wpedantic, "types are not quite compatible"); + + if (val == 1 && enum_and_int_p && warn_cxx_compat) + warning_at (location, OPT_Wc___compat, + "pointer target types incompatible in C++"); + + return val; +} + +/* Subroutines of `comptypes'. */ + +/* Determine whether two trees derive from the same translation unit. + If the CONTEXT chain ends in a null, that tree's context is still + being parsed, so if two trees have context chains ending in null, + they're in the same translation unit. */ +int +same_translation_unit_p (const_tree t1, const_tree t2) +{ + while (t1 && TREE_CODE (t1) != TRANSLATION_UNIT_DECL) + switch (TREE_CODE_CLASS (TREE_CODE (t1))) + { + case tcc_declaration: + t1 = DECL_CONTEXT (t1); break; + case tcc_type: + t1 = TYPE_CONTEXT (t1); break; + case tcc_exceptional: + t1 = BLOCK_SUPERCONTEXT (t1); break; /* assume block */ + default: gcc_unreachable (); + } + + while (t2 && TREE_CODE (t2) != TRANSLATION_UNIT_DECL) + switch (TREE_CODE_CLASS (TREE_CODE (t2))) + { + case tcc_declaration: + t2 = DECL_CONTEXT (t2); break; + case tcc_type: + t2 = TYPE_CONTEXT (t2); break; + case tcc_exceptional: + t2 = BLOCK_SUPERCONTEXT (t2); break; /* assume block */ + default: gcc_unreachable (); + } + + return t1 == t2; +} + +/* Allocate the seen two types, assuming that they are compatible. */ + +static struct tagged_tu_seen_cache * +alloc_tagged_tu_seen_cache (const_tree t1, const_tree t2) +{ + struct tagged_tu_seen_cache *tu = XNEW (struct tagged_tu_seen_cache); + tu->next = tagged_tu_seen_base; + tu->t1 = t1; + tu->t2 = t2; + + tagged_tu_seen_base = tu; + + /* The C standard says that two structures in different translation + units are compatible with each other only if the types of their + fields are compatible (among other things). We assume that they + are compatible until proven otherwise when building the cache. + An example where this can occur is: + struct a + { + struct a *next; + }; + If we are comparing this against a similar struct in another TU, + and did not assume they were compatible, we end up with an infinite + loop. */ + tu->val = 1; + return tu; +} + +/* Free the seen types until we get to TU_TIL. */ + +static void +free_all_tagged_tu_seen_up_to (const struct tagged_tu_seen_cache *tu_til) +{ + const struct tagged_tu_seen_cache *tu = tagged_tu_seen_base; + while (tu != tu_til) + { + const struct tagged_tu_seen_cache *const tu1 + = (const struct tagged_tu_seen_cache *) tu; + tu = tu1->next; + free (CONST_CAST (struct tagged_tu_seen_cache *, tu1)); + } + tagged_tu_seen_base = tu_til; +} + +/* Return 1 if two 'struct', 'union', or 'enum' types T1 and T2 are + compatible. If the two types are not the same (which has been + checked earlier), this can only happen when multiple translation + units are being compiled. See C99 6.2.7 paragraph 1 for the exact + rules. ENUM_AND_INT_P and DIFFERENT_TYPES_P are as in + comptypes_internal. */ + +static int +tagged_types_tu_compatible_p (const_tree t1, const_tree t2, + bool *enum_and_int_p, bool *different_types_p) +{ + tree s1, s2; + bool needs_warning = false; + + /* We have to verify that the tags of the types are the same. This + is harder than it looks because this may be a typedef, so we have + to go look at the original type. It may even be a typedef of a + typedef... + In the case of compiler-created builtin structs the TYPE_DECL + may be a dummy, with no DECL_ORIGINAL_TYPE. Don't fault. */ + while (TYPE_NAME (t1) + && TREE_CODE (TYPE_NAME (t1)) == TYPE_DECL + && DECL_ORIGINAL_TYPE (TYPE_NAME (t1))) + t1 = DECL_ORIGINAL_TYPE (TYPE_NAME (t1)); + + while (TYPE_NAME (t2) + && TREE_CODE (TYPE_NAME (t2)) == TYPE_DECL + && DECL_ORIGINAL_TYPE (TYPE_NAME (t2))) + t2 = DECL_ORIGINAL_TYPE (TYPE_NAME (t2)); + + /* C90 didn't have the requirement that the two tags be the same. */ + if (flag_isoc99 && TYPE_NAME (t1) != TYPE_NAME (t2)) + return 0; + + /* C90 didn't say what happened if one or both of the types were + incomplete; we choose to follow C99 rules here, which is that they + are compatible. */ + if (TYPE_SIZE (t1) == NULL + || TYPE_SIZE (t2) == NULL) + return 1; + + { + const struct tagged_tu_seen_cache * tts_i; + for (tts_i = tagged_tu_seen_base; tts_i != NULL; tts_i = tts_i->next) + if (tts_i->t1 == t1 && tts_i->t2 == t2) + return tts_i->val; + } + + switch (TREE_CODE (t1)) + { + case ENUMERAL_TYPE: + { + struct tagged_tu_seen_cache *tu = alloc_tagged_tu_seen_cache (t1, t2); + /* Speed up the case where the type values are in the same order. */ + tree tv1 = TYPE_VALUES (t1); + tree tv2 = TYPE_VALUES (t2); + + if (tv1 == tv2) + { + return 1; + } + + for (;tv1 && tv2; tv1 = TREE_CHAIN (tv1), tv2 = TREE_CHAIN (tv2)) + { + if (TREE_PURPOSE (tv1) != TREE_PURPOSE (tv2)) + break; + if (simple_cst_equal (TREE_VALUE (tv1), TREE_VALUE (tv2)) != 1) + { + tu->val = 0; + return 0; + } + } + + if (tv1 == NULL_TREE && tv2 == NULL_TREE) + { + return 1; + } + if (tv1 == NULL_TREE || tv2 == NULL_TREE) + { + tu->val = 0; + return 0; + } + + if (list_length (TYPE_VALUES (t1)) != list_length (TYPE_VALUES (t2))) + { + tu->val = 0; + return 0; + } + + for (s1 = TYPE_VALUES (t1); s1; s1 = TREE_CHAIN (s1)) + { + s2 = purpose_member (TREE_PURPOSE (s1), TYPE_VALUES (t2)); + if (s2 == NULL + || simple_cst_equal (TREE_VALUE (s1), TREE_VALUE (s2)) != 1) + { + tu->val = 0; + return 0; + } + } + return 1; + } + + case UNION_TYPE: + { + struct tagged_tu_seen_cache *tu = alloc_tagged_tu_seen_cache (t1, t2); + if (list_length (TYPE_FIELDS (t1)) != list_length (TYPE_FIELDS (t2))) + { + tu->val = 0; + return 0; + } + + /* Speed up the common case where the fields are in the same order. */ + for (s1 = TYPE_FIELDS (t1), s2 = TYPE_FIELDS (t2); s1 && s2; + s1 = DECL_CHAIN (s1), s2 = DECL_CHAIN (s2)) + { + int result; + + if (DECL_NAME (s1) != DECL_NAME (s2)) + break; + result = comptypes_internal (TREE_TYPE (s1), TREE_TYPE (s2), + enum_and_int_p, different_types_p); + + if (result != 1 && !DECL_NAME (s1)) + break; + if (result == 0) + { + tu->val = 0; + return 0; + } + if (result == 2) + needs_warning = true; + + if (TREE_CODE (s1) == FIELD_DECL + && simple_cst_equal (DECL_FIELD_BIT_OFFSET (s1), + DECL_FIELD_BIT_OFFSET (s2)) != 1) + { + tu->val = 0; + return 0; + } + } + if (!s1 && !s2) + { + tu->val = needs_warning ? 2 : 1; + return tu->val; + } + + for (s1 = TYPE_FIELDS (t1); s1; s1 = DECL_CHAIN (s1)) + { + bool ok = false; + + for (s2 = TYPE_FIELDS (t2); s2; s2 = DECL_CHAIN (s2)) + if (DECL_NAME (s1) == DECL_NAME (s2)) + { + int result; + + result = comptypes_internal (TREE_TYPE (s1), TREE_TYPE (s2), + enum_and_int_p, + different_types_p); + + if (result != 1 && !DECL_NAME (s1)) + continue; + if (result == 0) + { + tu->val = 0; + return 0; + } + if (result == 2) + needs_warning = true; + + if (TREE_CODE (s1) == FIELD_DECL + && simple_cst_equal (DECL_FIELD_BIT_OFFSET (s1), + DECL_FIELD_BIT_OFFSET (s2)) != 1) + break; + + ok = true; + break; + } + if (!ok) + { + tu->val = 0; + return 0; + } + } + tu->val = needs_warning ? 2 : 10; + return tu->val; + } + + case RECORD_TYPE: + { + struct tagged_tu_seen_cache *tu = alloc_tagged_tu_seen_cache (t1, t2); + + for (s1 = TYPE_FIELDS (t1), s2 = TYPE_FIELDS (t2); + s1 && s2; + s1 = DECL_CHAIN (s1), s2 = DECL_CHAIN (s2)) + { + int result; + if (TREE_CODE (s1) != TREE_CODE (s2) + || DECL_NAME (s1) != DECL_NAME (s2)) + break; + result = comptypes_internal (TREE_TYPE (s1), TREE_TYPE (s2), + enum_and_int_p, different_types_p); + if (result == 0) + break; + if (result == 2) + needs_warning = true; + + if (TREE_CODE (s1) == FIELD_DECL + && simple_cst_equal (DECL_FIELD_BIT_OFFSET (s1), + DECL_FIELD_BIT_OFFSET (s2)) != 1) + break; + } + if (s1 && s2) + tu->val = 0; + else + tu->val = needs_warning ? 2 : 1; + return tu->val; + } + + default: + gcc_unreachable (); + } +} + +/* 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. + ENUM_AND_INT_P and DIFFERENT_TYPES_P are as in comptypes_internal. */ + +static int +function_types_compatible_p (const_tree f1, const_tree f2, + bool *enum_and_int_p, bool *different_types_p) +{ + tree args1, args2; + /* 1 if no need for warning yet, 2 if warning cause has been seen. */ + int val = 1; + int val1; + tree ret1, ret2; + + ret1 = TREE_TYPE (f1); + ret2 = TREE_TYPE (f2); + + /* 'volatile' qualifiers on a function's return type used to mean + the function is noreturn. */ + if (TYPE_VOLATILE (ret1) != TYPE_VOLATILE (ret2)) + pedwarn (input_location, 0, "function return types not compatible due to %<volatile%>"); + if (TYPE_VOLATILE (ret1)) + ret1 = build_qualified_type (TYPE_MAIN_VARIANT (ret1), + TYPE_QUALS (ret1) & ~TYPE_QUAL_VOLATILE); + if (TYPE_VOLATILE (ret2)) + ret2 = build_qualified_type (TYPE_MAIN_VARIANT (ret2), + TYPE_QUALS (ret2) & ~TYPE_QUAL_VOLATILE); + val = comptypes_internal (ret1, ret2, enum_and_int_p, different_types_p); + if (val == 0) + return 0; + + args1 = TYPE_ARG_TYPES (f1); + args2 = TYPE_ARG_TYPES (f2); + + if (different_types_p != NULL + && (args1 == 0) != (args2 == 0)) + *different_types_p = true; + + /* 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), + enum_and_int_p, different_types_p)) + 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), + enum_and_int_p, different_types_p)) + val = 2; + return val; + } + + /* Both types have argument lists: compare them and propagate results. */ + val1 = type_lists_compatible_p (args1, args2, enum_and_int_p, + different_types_p); + 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. ENUM_AND_INT_P and DIFFERENT_TYPES_P are as in + comptypes_internal. */ + +static int +type_lists_compatible_p (const_tree args1, const_tree args2, + bool *enum_and_int_p, bool *different_types_p) +{ + /* 1 if no need for warning yet, 2 if warning cause has been seen. */ + int val = 1; + int newval = 0; + + while (1) + { + tree a1, mv1, a2, mv2; + 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; + mv1 = a1 = TREE_VALUE (args1); + mv2 = a2 = TREE_VALUE (args2); + if (mv1 && mv1 != error_mark_node && TREE_CODE (mv1) != ARRAY_TYPE) + mv1 = TYPE_MAIN_VARIANT (mv1); + if (mv2 && mv2 != error_mark_node && TREE_CODE (mv2) != ARRAY_TYPE) + mv2 = TYPE_MAIN_VARIANT (mv2); + /* 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 (different_types_p != NULL + && (a1 == 0) != (a2 == 0)) + *different_types_p = true; + if (a1 == 0) + { + if (c_type_promotes_to (a2) != a2) + return 0; + } + else if (a2 == 0) + { + if (c_type_promotes_to (a1) != a1) + return 0; + } + /* If one of the lists has an error marker, ignore this arg. */ + else if (TREE_CODE (a1) == ERROR_MARK + || TREE_CODE (a2) == ERROR_MARK) + ; + else if (!(newval = comptypes_internal (mv1, mv2, enum_and_int_p, + different_types_p))) + { + if (different_types_p != NULL) + *different_types_p = true; + /* Allow wait (union {union wait *u; int *i} *) + and wait (union wait *) to be compatible. */ + if (TREE_CODE (a1) == UNION_TYPE + && (TYPE_NAME (a1) == 0 + || TYPE_TRANSPARENT_AGGR (a1)) + && TREE_CODE (TYPE_SIZE (a1)) == INTEGER_CST + && tree_int_cst_equal (TYPE_SIZE (a1), + TYPE_SIZE (a2))) + { + tree memb; + for (memb = TYPE_FIELDS (a1); + memb; memb = DECL_CHAIN (memb)) + { + tree mv3 = TREE_TYPE (memb); + if (mv3 && mv3 != error_mark_node + && TREE_CODE (mv3) != ARRAY_TYPE) + mv3 = TYPE_MAIN_VARIANT (mv3); + if (comptypes_internal (mv3, mv2, enum_and_int_p, + different_types_p)) + break; + } + if (memb == 0) + return 0; + } + else if (TREE_CODE (a2) == UNION_TYPE + && (TYPE_NAME (a2) == 0 + || TYPE_TRANSPARENT_AGGR (a2)) + && TREE_CODE (TYPE_SIZE (a2)) == INTEGER_CST + && tree_int_cst_equal (TYPE_SIZE (a2), + TYPE_SIZE (a1))) + { + tree memb; + for (memb = TYPE_FIELDS (a2); + memb; memb = DECL_CHAIN (memb)) + { + tree mv3 = TREE_TYPE (memb); + if (mv3 && mv3 != error_mark_node + && TREE_CODE (mv3) != ARRAY_TYPE) + mv3 = TYPE_MAIN_VARIANT (mv3); + if (comptypes_internal (mv3, mv1, enum_and_int_p, + different_types_p)) + 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); + } +} + +/* Compute the size to increment a pointer by. */ + +static tree +c_size_in_bytes (const_tree type) +{ + enum tree_code code = TREE_CODE (type); + + if (code == FUNCTION_TYPE || code == VOID_TYPE || code == ERROR_MARK) + return size_one_node; + + if (!COMPLETE_OR_VOID_TYPE_P (type)) + { + error ("arithmetic on pointer to an incomplete type"); + return size_one_node; + } + + /* Convert in case a char is more than one unit. */ + return size_binop_loc (input_location, CEIL_DIV_EXPR, TYPE_SIZE_UNIT (type), + size_int (TYPE_PRECISION (char_type_node) + / BITS_PER_UNIT)); +} + +/* Return either DECL or its known constant value (if it has one). */ + +tree +decl_constant_value (tree decl) +{ + if (/* Don't change a variable array bound or initial value to a constant + in a place where a variable is invalid. Note that DECL_INITIAL + isn't valid for a PARM_DECL. */ + current_function_decl != 0 + && TREE_CODE (decl) != PARM_DECL + && !TREE_THIS_VOLATILE (decl) + && TREE_READONLY (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) + return DECL_INITIAL (decl); + return decl; +} + +/* Convert the array expression EXP to a pointer. */ +static tree +array_to_pointer_conversion (location_t loc, tree exp) +{ + tree orig_exp = exp; + tree type = TREE_TYPE (exp); + tree adr; + tree restype = TREE_TYPE (type); + tree ptrtype; + + gcc_assert (TREE_CODE (type) == ARRAY_TYPE); + + STRIP_TYPE_NOPS (exp); + + if (TREE_NO_WARNING (orig_exp)) + TREE_NO_WARNING (exp) = 1; + + ptrtype = build_pointer_type (restype); + + if (TREE_CODE (exp) == INDIRECT_REF) + return convert (ptrtype, TREE_OPERAND (exp, 0)); + + /* In C++ array compound literals are temporary objects unless they are + const or appear in namespace scope, so they are destroyed too soon + to use them for much of anything (c++/53220). */ + if (warn_cxx_compat && TREE_CODE (exp) == COMPOUND_LITERAL_EXPR) + { + tree decl = TREE_OPERAND (TREE_OPERAND (exp, 0), 0); + if (!TREE_READONLY (decl) && !TREE_STATIC (decl)) + warning_at (DECL_SOURCE_LOCATION (decl), OPT_Wc___compat, + "converting an array compound literal to a pointer " + "is ill-formed in C++"); + } + + adr = build_unary_op (loc, ADDR_EXPR, exp, 1); + return convert (ptrtype, adr); +} + +/* Convert the function expression EXP to a pointer. */ +static tree +function_to_pointer_conversion (location_t loc, tree exp) +{ + tree orig_exp = exp; + + gcc_assert (TREE_CODE (TREE_TYPE (exp)) == FUNCTION_TYPE); + + STRIP_TYPE_NOPS (exp); + + if (TREE_NO_WARNING (orig_exp)) + TREE_NO_WARNING (exp) = 1; + + return build_unary_op (loc, ADDR_EXPR, exp, 0); +} + +/* Mark EXP as read, not just set, for set but not used -Wunused + warning purposes. */ + +void +mark_exp_read (tree exp) +{ + switch (TREE_CODE (exp)) + { + case VAR_DECL: + case PARM_DECL: + DECL_READ_P (exp) = 1; + break; + case ARRAY_REF: + case COMPONENT_REF: + case MODIFY_EXPR: + case REALPART_EXPR: + case IMAGPART_EXPR: + CASE_CONVERT: + case ADDR_EXPR: + mark_exp_read (TREE_OPERAND (exp, 0)); + break; + case COMPOUND_EXPR: + case C_MAYBE_CONST_EXPR: + mark_exp_read (TREE_OPERAND (exp, 1)); + break; + default: + break; + } +} + +/* Perform the default conversion of arrays and functions to pointers. + Return the result of converting EXP. For any other expression, just + return EXP. + + LOC is the location of the expression. */ + +struct c_expr +default_function_array_conversion (location_t loc, struct c_expr exp) +{ + tree orig_exp = exp.value; + tree type = TREE_TYPE (exp.value); + enum tree_code code = TREE_CODE (type); + + switch (code) + { + case ARRAY_TYPE: + { + bool not_lvalue = false; + bool lvalue_array_p; + + while ((TREE_CODE (exp.value) == NON_LVALUE_EXPR + || CONVERT_EXPR_P (exp.value)) + && TREE_TYPE (TREE_OPERAND (exp.value, 0)) == type) + { + if (TREE_CODE (exp.value) == NON_LVALUE_EXPR) + not_lvalue = true; + exp.value = TREE_OPERAND (exp.value, 0); + } + + if (TREE_NO_WARNING (orig_exp)) + TREE_NO_WARNING (exp.value) = 1; + + lvalue_array_p = !not_lvalue && lvalue_p (exp.value); + if (!flag_isoc99 && !lvalue_array_p) + { + /* Before C99, non-lvalue arrays do not decay to pointers. + Normally, using such an array would be invalid; but it can + be used correctly inside sizeof or as a statement expression. + Thus, do not give an error here; an error will result later. */ + return exp; + } + + exp.value = array_to_pointer_conversion (loc, exp.value); + } + break; + case FUNCTION_TYPE: + exp.value = function_to_pointer_conversion (loc, exp.value); + break; + default: + break; + } + + return exp; +} + +struct c_expr +default_function_array_read_conversion (location_t loc, struct c_expr exp) +{ + mark_exp_read (exp.value); + return default_function_array_conversion (loc, exp); +} + +/* EXP is an expression of integer type. Apply the integer promotions + to it and return the promoted value. */ + +tree +perform_integral_promotions (tree exp) +{ + tree type = TREE_TYPE (exp); + enum tree_code code = TREE_CODE (type); + + gcc_assert (INTEGRAL_TYPE_P (type)); + + /* Normally convert enums to int, + but convert wide enums to something wider. */ + if (code == ENUMERAL_TYPE) + { + type = c_common_type_for_size (MAX (TYPE_PRECISION (type), + TYPE_PRECISION (integer_type_node)), + ((TYPE_PRECISION (type) + >= TYPE_PRECISION (integer_type_node)) + && TYPE_UNSIGNED (type))); + + return convert (type, exp); + } + + /* ??? This should no longer be needed now bit-fields have their + proper types. */ + if (TREE_CODE (exp) == COMPONENT_REF + && DECL_C_BIT_FIELD (TREE_OPERAND (exp, 1)) + /* If it's thinner than an int, promote it like a + c_promoting_integer_type_p, otherwise leave it alone. */ + && 0 > compare_tree_int (DECL_SIZE (TREE_OPERAND (exp, 1)), + TYPE_PRECISION (integer_type_node))) + return convert (integer_type_node, exp); + + if (c_promoting_integer_type_p (type)) + { + /* Preserve unsignedness if not really getting any wider. */ + if (TYPE_UNSIGNED (type) + && TYPE_PRECISION (type) == TYPE_PRECISION (integer_type_node)) + return convert (unsigned_type_node, exp); + + return convert (integer_type_node, exp); + } + + return exp; +} + + +/* Perform default promotions for C data used in expressions. + Enumeral types or short or char are converted to int. + In addition, manifest constants symbols are replaced by their values. */ + +tree +default_conversion (tree exp) +{ + tree orig_exp; + tree type = TREE_TYPE (exp); + enum tree_code code = TREE_CODE (type); + tree promoted_type; + + mark_exp_read (exp); + + /* Functions and arrays have been converted during parsing. */ + gcc_assert (code != FUNCTION_TYPE); + if (code == ARRAY_TYPE) + return exp; + + /* Constants can be used directly unless they're not loadable. */ + if (TREE_CODE (exp) == CONST_DECL) + exp = DECL_INITIAL (exp); + + /* Strip no-op conversions. */ + orig_exp = exp; + STRIP_TYPE_NOPS (exp); + + if (TREE_NO_WARNING (orig_exp)) + TREE_NO_WARNING (exp) = 1; + + if (code == VOID_TYPE) + { + error ("void value not ignored as it ought to be"); + return error_mark_node; + } + + exp = require_complete_type (exp); + if (exp == error_mark_node) + return error_mark_node; + + promoted_type = targetm.promoted_type (type); + if (promoted_type) + return convert (promoted_type, exp); + + if (INTEGRAL_TYPE_P (type)) + return perform_integral_promotions (exp); + + return exp; +} + +/* Look up COMPONENT in a structure or union TYPE. + + If the component name is not found, returns NULL_TREE. Otherwise, + the return value is a TREE_LIST, with each TREE_VALUE a FIELD_DECL + stepping down the chain to the component, which is in the last + TREE_VALUE of the list. Normally the list is of length one, but if + the component is embedded within (nested) anonymous structures or + unions, the list steps down the chain to the component. */ + +static tree +lookup_field (tree type, tree component) +{ + 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) && TYPE_LANG_SPECIFIC (type)->s) + { + int bot, top, half; + tree *field_array = &TYPE_LANG_SPECIFIC (type)->s->elts[0]; + + field = TYPE_FIELDS (type); + bot = 0; + top = TYPE_LANG_SPECIFIC (type)->s->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) + { + field = field_array[bot++]; + if (TREE_CODE (TREE_TYPE (field)) == RECORD_TYPE + || TREE_CODE (TREE_TYPE (field)) == UNION_TYPE) + { + tree anon = lookup_field (TREE_TYPE (field), component); + + if (anon) + return tree_cons (NULL_TREE, field, anon); + + /* The Plan 9 compiler permits referring + directly to an anonymous struct/union field + using a typedef name. */ + if (flag_plan9_extensions + && TYPE_NAME (TREE_TYPE (field)) != NULL_TREE + && (TREE_CODE (TYPE_NAME (TREE_TYPE (field))) + == TYPE_DECL) + && (DECL_NAME (TYPE_NAME (TREE_TYPE (field))) + == component)) + break; + } + } + + /* 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) + return NULL_TREE; + } + else + { + for (field = TYPE_FIELDS (type); field; field = DECL_CHAIN (field)) + { + if (DECL_NAME (field) == NULL_TREE + && (TREE_CODE (TREE_TYPE (field)) == RECORD_TYPE + || TREE_CODE (TREE_TYPE (field)) == UNION_TYPE)) + { + tree anon = lookup_field (TREE_TYPE (field), component); + + if (anon) + return tree_cons (NULL_TREE, field, anon); + + /* The Plan 9 compiler permits referring directly to an + anonymous struct/union field using a typedef + name. */ + if (flag_plan9_extensions + && TYPE_NAME (TREE_TYPE (field)) != NULL_TREE + && TREE_CODE (TYPE_NAME (TREE_TYPE (field))) == TYPE_DECL + && (DECL_NAME (TYPE_NAME (TREE_TYPE (field))) + == component)) + break; + } + + if (DECL_NAME (field) == component) + break; + } + + if (field == NULL_TREE) + return NULL_TREE; + } + + return tree_cons (NULL_TREE, field, NULL_TREE); +} + +/* Make an expression to refer to the COMPONENT field of structure or + union value DATUM. COMPONENT is an IDENTIFIER_NODE. LOC is the + location of the COMPONENT_REF. */ + +tree +build_component_ref (location_t loc, tree datum, tree component) +{ + tree type = TREE_TYPE (datum); + enum tree_code code = TREE_CODE (type); + tree field = NULL; + tree ref; + bool datum_lvalue = lvalue_p (datum); + + if (!objc_is_public (datum, component)) + return error_mark_node; + + /* Detect Objective-C property syntax object.property. */ + if (c_dialect_objc () + && (ref = objc_maybe_build_component_ref (datum, component))) + return ref; + + /* See if there is a field or component with name COMPONENT. */ + + if (code == RECORD_TYPE || code == UNION_TYPE) + { + if (!COMPLETE_TYPE_P (type)) + { + c_incomplete_type_error (NULL_TREE, type); + return error_mark_node; + } + + field = lookup_field (type, component); + + if (!field) + { + error_at (loc, "%qT has no member named %qE", type, component); + return error_mark_node; + } + + /* Chain the COMPONENT_REFs if necessary down to the FIELD. + This might be better solved in future the way the C++ front + end does it - by giving the anonymous entities each a + separate name and type, and then have build_component_ref + recursively call itself. We can't do that here. */ + do + { + tree subdatum = TREE_VALUE (field); + int quals; + tree subtype; + bool use_datum_quals; + + if (TREE_TYPE (subdatum) == error_mark_node) + return error_mark_node; + + /* If this is an rvalue, it does not have qualifiers in C + standard terms and we must avoid propagating such + qualifiers down to a non-lvalue array that is then + converted to a pointer. */ + use_datum_quals = (datum_lvalue + || TREE_CODE (TREE_TYPE (subdatum)) != ARRAY_TYPE); + + quals = TYPE_QUALS (strip_array_types (TREE_TYPE (subdatum))); + if (use_datum_quals) + quals |= TYPE_QUALS (TREE_TYPE (datum)); + subtype = c_build_qualified_type (TREE_TYPE (subdatum), quals); + + ref = build3 (COMPONENT_REF, subtype, datum, subdatum, + NULL_TREE); + SET_EXPR_LOCATION (ref, loc); + if (TREE_READONLY (subdatum) + || (use_datum_quals && TREE_READONLY (datum))) + TREE_READONLY (ref) = 1; + if (TREE_THIS_VOLATILE (subdatum) + || (use_datum_quals && TREE_THIS_VOLATILE (datum))) + TREE_THIS_VOLATILE (ref) = 1; + + if (TREE_DEPRECATED (subdatum)) + warn_deprecated_use (subdatum, NULL_TREE); + + datum = ref; + + field = TREE_CHAIN (field); + } + while (field); + + return ref; + } + else if (code != ERROR_MARK) + error_at (loc, + "request for member %qE in something not a structure or union", + 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. + + LOC is the location to use for the generated tree. */ + +tree +build_indirect_ref (location_t loc, tree ptr, ref_operator errstring) +{ + tree pointer = default_conversion (ptr); + tree type = TREE_TYPE (pointer); + tree ref; + + if (TREE_CODE (type) == POINTER_TYPE) + { + if (CONVERT_EXPR_P (pointer) + || TREE_CODE (pointer) == VIEW_CONVERT_EXPR) + { + /* If a warning is issued, mark it to avoid duplicates from + the backend. This only needs to be done at + warn_strict_aliasing > 2. */ + if (warn_strict_aliasing > 2) + if (strict_aliasing_warning (TREE_TYPE (TREE_OPERAND (pointer, 0)), + type, TREE_OPERAND (pointer, 0))) + TREE_NO_WARNING (pointer) = 1; + } + + if (TREE_CODE (pointer) == ADDR_EXPR + && (TREE_TYPE (TREE_OPERAND (pointer, 0)) + == TREE_TYPE (type))) + { + ref = TREE_OPERAND (pointer, 0); + protected_set_expr_location (ref, loc); + return ref; + } + else + { + tree t = TREE_TYPE (type); + + ref = build1 (INDIRECT_REF, t, pointer); + + if (!COMPLETE_OR_VOID_TYPE_P (t) && TREE_CODE (t) != ARRAY_TYPE) + { + error_at (loc, "dereferencing pointer to incomplete type"); + return error_mark_node; + } + if (VOID_TYPE_P (t) && c_inhibit_evaluation_warnings == 0) + warning_at (loc, 0, "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); + TREE_THIS_VOLATILE (ref) = TYPE_VOLATILE (t); + protected_set_expr_location (ref, loc); + return ref; + } + } + else if (TREE_CODE (pointer) != ERROR_MARK) + invalid_indirection_error (loc, type, errstring); + + 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). + + For vector types, allow vector[i] but not i[vector], and create + *(((type*)&vectortype) + i) for the expression. + + LOC is the location to use for the returned expression. */ + +tree +build_array_ref (location_t loc, tree array, tree index) +{ + tree ret; + bool swapped = false; + 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 (TREE_TYPE (array)) != POINTER_TYPE + /* Allow vector[index] but not index[vector]. */ + && TREE_CODE (TREE_TYPE (array)) != VECTOR_TYPE) + { + tree temp; + if (TREE_CODE (TREE_TYPE (index)) != ARRAY_TYPE + && TREE_CODE (TREE_TYPE (index)) != POINTER_TYPE) + { + error_at (loc, + "subscripted value is neither array nor pointer nor vector"); + + return error_mark_node; + } + temp = array; + array = index; + index = temp; + swapped = true; + } + + if (!INTEGRAL_TYPE_P (TREE_TYPE (index))) + { + error_at (loc, "array subscript is not an integer"); + return error_mark_node; + } + + if (TREE_CODE (TREE_TYPE (TREE_TYPE (array))) == FUNCTION_TYPE) + { + error_at (loc, "subscripted value is pointer to function"); + return error_mark_node; + } + + /* ??? Existing practice has been to warn only when the char + index is syntactically the index, not for char[array]. */ + if (!swapped) + warn_array_subscript_with_type_char (index); + + /* Apply default promotions *after* noticing character types. */ + index = default_conversion (index); + + gcc_assert (TREE_CODE (TREE_TYPE (index)) == INTEGER_TYPE); + + convert_vector_to_pointer_for_subscript (loc, &array, index); + + if (TREE_CODE (TREE_TYPE (array)) == ARRAY_TYPE) + { + tree rval, type; + + /* 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 + || (COMPLETE_TYPE_P (TREE_TYPE (TREE_TYPE (array))) + && TREE_CODE (TYPE_SIZE (TREE_TYPE (TREE_TYPE (array)))) != INTEGER_CST)) + { + if (!c_mark_addressable (array)) + 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_DOMAIN (TREE_TYPE (array)) + && !int_fits_type_p (index, TYPE_DOMAIN (TREE_TYPE (array)))) + { + if (!c_mark_addressable (array)) + return error_mark_node; + } + + if (pedantic) + { + tree foo = array; + while (TREE_CODE (foo) == COMPONENT_REF) + foo = TREE_OPERAND (foo, 0); + if (TREE_CODE (foo) == VAR_DECL && C_DECL_REGISTER (foo)) + pedwarn (loc, OPT_Wpedantic, + "ISO C forbids subscripting %<register%> array"); + else if (!flag_isoc99 && !lvalue_p (foo)) + pedwarn (loc, OPT_Wpedantic, + "ISO C90 forbids subscripting non-lvalue array"); + } + + type = TREE_TYPE (TREE_TYPE (array)); + rval = build4 (ARRAY_REF, type, array, index, NULL_TREE, NULL_TREE); + /* 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)); + ret = require_complete_type (rval); + protected_set_expr_location (ret, loc); + return ret; + } + else + { + tree ar = default_conversion (array); + + if (ar == error_mark_node) + return ar; + + gcc_assert (TREE_CODE (TREE_TYPE (ar)) == POINTER_TYPE); + gcc_assert (TREE_CODE (TREE_TYPE (TREE_TYPE (ar))) != FUNCTION_TYPE); + + return build_indirect_ref + (loc, build_binary_op (loc, PLUS_EXPR, ar, index, 0), + RO_ARRAY_INDEXING); + } +} + +/* Build an external reference to identifier ID. FUN indicates + whether this will be used for a function call. LOC is the source + location of the identifier. This sets *TYPE to the type of the + identifier, which is not the same as the type of the returned value + for CONST_DECLs defined as enum constants. If the type of the + identifier is not available, *TYPE is set to NULL. */ +tree +build_external_ref (location_t loc, tree id, int fun, tree *type) +{ + tree ref; + tree decl = lookup_name (id); + + /* In Objective-C, an instance variable (ivar) may be preferred to + whatever lookup_name() found. */ + decl = objc_lookup_ivar (decl, id); + + *type = NULL; + if (decl && decl != error_mark_node) + { + ref = decl; + *type = TREE_TYPE (ref); + } + else if (fun) + /* Implicit function declaration. */ + ref = implicitly_declare (loc, id); + else if (decl == error_mark_node) + /* Don't complain about something that's already been + complained about. */ + return error_mark_node; + else + { + undeclared_variable (loc, id); + return error_mark_node; + } + + if (TREE_TYPE (ref) == error_mark_node) + return error_mark_node; + + if (TREE_DEPRECATED (ref)) + warn_deprecated_use (ref, NULL_TREE); + + /* Recursive call does not count as usage. */ + if (ref != current_function_decl) + { + TREE_USED (ref) = 1; + } + + if (TREE_CODE (ref) == FUNCTION_DECL && !in_alignof) + { + if (!in_sizeof && !in_typeof) + C_DECL_USED (ref) = 1; + else if (DECL_INITIAL (ref) == 0 + && DECL_EXTERNAL (ref) + && !TREE_PUBLIC (ref)) + record_maybe_used_decl (ref); + } + + if (TREE_CODE (ref) == CONST_DECL) + { + used_types_insert (TREE_TYPE (ref)); + + if (warn_cxx_compat + && TREE_CODE (TREE_TYPE (ref)) == ENUMERAL_TYPE + && C_TYPE_DEFINED_IN_STRUCT (TREE_TYPE (ref))) + { + warning_at (loc, OPT_Wc___compat, + ("enum constant defined in struct or union " + "is not visible in C++")); + inform (DECL_SOURCE_LOCATION (ref), "enum constant defined here"); + } + + ref = DECL_INITIAL (ref); + TREE_CONSTANT (ref) = 1; + } + else if (current_function_decl != 0 + && !DECL_FILE_SCOPE_P (current_function_decl) + && (TREE_CODE (ref) == VAR_DECL + || TREE_CODE (ref) == PARM_DECL + || TREE_CODE (ref) == FUNCTION_DECL)) + { + tree context = decl_function_context (ref); + + if (context != 0 && context != current_function_decl) + DECL_NONLOCAL (ref) = 1; + } + /* C99 6.7.4p3: An inline definition of a function with external + linkage ... shall not contain a reference to an identifier with + internal linkage. */ + else if (current_function_decl != 0 + && DECL_DECLARED_INLINE_P (current_function_decl) + && DECL_EXTERNAL (current_function_decl) + && VAR_OR_FUNCTION_DECL_P (ref) + && (TREE_CODE (ref) != VAR_DECL || TREE_STATIC (ref)) + && ! TREE_PUBLIC (ref) + && DECL_CONTEXT (ref) != current_function_decl) + record_inline_static (loc, current_function_decl, ref, + csi_internal); + + return ref; +} + +/* Record details of decls possibly used inside sizeof or typeof. */ +struct maybe_used_decl +{ + /* The decl. */ + tree decl; + /* The level seen at (in_sizeof + in_typeof). */ + int level; + /* The next one at this level or above, or NULL. */ + struct maybe_used_decl *next; +}; + +static struct maybe_used_decl *maybe_used_decls; + +/* Record that DECL, an undefined static function reference seen + inside sizeof or typeof, might be used if the operand of sizeof is + a VLA type or the operand of typeof is a variably modified + type. */ + +static void +record_maybe_used_decl (tree decl) +{ + struct maybe_used_decl *t = XOBNEW (&parser_obstack, struct maybe_used_decl); + t->decl = decl; + t->level = in_sizeof + in_typeof; + t->next = maybe_used_decls; + maybe_used_decls = t; +} + +/* Pop the stack of decls possibly used inside sizeof or typeof. If + USED is false, just discard them. If it is true, mark them used + (if no longer inside sizeof or typeof) or move them to the next + level up (if still inside sizeof or typeof). */ + +void +pop_maybe_used (bool used) +{ + struct maybe_used_decl *p = maybe_used_decls; + int cur_level = in_sizeof + in_typeof; + while (p && p->level > cur_level) + { + if (used) + { + if (cur_level == 0) + C_DECL_USED (p->decl) = 1; + else + p->level = cur_level; + } + p = p->next; + } + if (!used || cur_level == 0) + maybe_used_decls = p; +} + +/* Return the result of sizeof applied to EXPR. */ + +struct c_expr +c_expr_sizeof_expr (location_t loc, struct c_expr expr) +{ + struct c_expr ret; + if (expr.value == error_mark_node) + { + ret.value = error_mark_node; + ret.original_code = ERROR_MARK; + ret.original_type = NULL; + pop_maybe_used (false); + } + else + { + bool expr_const_operands = true; + tree folded_expr = c_fully_fold (expr.value, require_constant_value, + &expr_const_operands); + ret.value = c_sizeof (loc, TREE_TYPE (folded_expr)); + ret.original_code = ERROR_MARK; + ret.original_type = NULL; + if (c_vla_type_p (TREE_TYPE (folded_expr))) + { + /* sizeof is evaluated when given a vla (C99 6.5.3.4p2). */ + ret.value = build2 (C_MAYBE_CONST_EXPR, TREE_TYPE (ret.value), + folded_expr, ret.value); + C_MAYBE_CONST_EXPR_NON_CONST (ret.value) = !expr_const_operands; + SET_EXPR_LOCATION (ret.value, loc); + } + pop_maybe_used (C_TYPE_VARIABLE_SIZE (TREE_TYPE (folded_expr))); + } + return ret; +} + +/* Return the result of sizeof applied to T, a structure for the type + name passed to sizeof (rather than the type itself). LOC is the + location of the original expression. */ + +struct c_expr +c_expr_sizeof_type (location_t loc, struct c_type_name *t) +{ + tree type; + struct c_expr ret; + tree type_expr = NULL_TREE; + bool type_expr_const = true; + type = groktypename (t, &type_expr, &type_expr_const); + ret.value = c_sizeof (loc, type); + ret.original_code = ERROR_MARK; + ret.original_type = NULL; + if ((type_expr || TREE_CODE (ret.value) == INTEGER_CST) + && c_vla_type_p (type)) + { + /* If the type is a [*] array, it is a VLA but is represented as + having a size of zero. In such a case we must ensure that + the result of sizeof does not get folded to a constant by + c_fully_fold, because if the size is evaluated the result is + not constant and so constraints on zero or negative size + arrays must not be applied when this sizeof call is inside + another array declarator. */ + if (!type_expr) + type_expr = integer_zero_node; + ret.value = build2 (C_MAYBE_CONST_EXPR, TREE_TYPE (ret.value), + type_expr, ret.value); + C_MAYBE_CONST_EXPR_NON_CONST (ret.value) = !type_expr_const; + } + pop_maybe_used (type != error_mark_node + ? C_TYPE_VARIABLE_SIZE (type) : false); + return ret; +} + +/* Build a function call to function FUNCTION with parameters PARAMS. + The function call is at LOC. + 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 (location_t loc, tree function, tree params) +{ + VEC(tree,gc) *vec; + tree ret; + + vec = VEC_alloc (tree, gc, list_length (params)); + for (; params; params = TREE_CHAIN (params)) + VEC_quick_push (tree, vec, TREE_VALUE (params)); + ret = build_function_call_vec (loc, function, vec, NULL); + VEC_free (tree, gc, vec); + return ret; +} + +/* Give a note about the location of the declaration of DECL. */ + +static void inform_declaration (tree decl) +{ + if (decl && (TREE_CODE (decl) != FUNCTION_DECL || !DECL_BUILT_IN (decl))) + inform (DECL_SOURCE_LOCATION (decl), "declared here"); +} + +/* Build a function call to function FUNCTION with parameters PARAMS. + ORIGTYPES, if not NULL, is a vector of types; each element is + either NULL or the original type of the corresponding element in + PARAMS. The original type may differ from TREE_TYPE of the + parameter for enums. FUNCTION's data type may be a function type + or pointer-to-function. This function changes the elements of + PARAMS. */ + +tree +build_function_call_vec (location_t loc, tree function, VEC(tree,gc) *params, + VEC(tree,gc) *origtypes) +{ + tree fntype, fundecl = 0; + tree name = NULL_TREE, result; + tree tem; + int nargs; + tree *argarray; + + + /* Strip NON_LVALUE_EXPRs, etc., since we aren't using as an lvalue. */ + STRIP_TYPE_NOPS (function); + + /* Convert anything with function type to a pointer-to-function. */ + if (TREE_CODE (function) == FUNCTION_DECL) + { + /* Implement type-directed function overloading for builtins. + resolve_overloaded_builtin and targetm.resolve_overloaded_builtin + handle all the type checking. The result is a complete expression + that implements this function call. */ + tem = resolve_overloaded_builtin (loc, function, params); + if (tem) + return tem; + + name = DECL_NAME (function); + + if (flag_tm) + tm_malloc_replacement (function); + fundecl = function; + /* Atomic functions have type checking/casting already done. They are + often rewritten and don't match the original parameter list. */ + if (name && !strncmp (IDENTIFIER_POINTER (name), "__atomic_", 9)) + origtypes = NULL; + } + if (TREE_CODE (TREE_TYPE (function)) == FUNCTION_TYPE) + function = function_to_pointer_conversion (loc, function); + + /* For Objective-C, convert any calls via a cast to OBJC_TYPE_REF + expressions, like those used for ObjC messenger dispatches. */ + if (!VEC_empty (tree, params)) + function = objc_rewrite_function_call (function, + VEC_index (tree, params, 0)); + + function = c_fully_fold (function, false, NULL); + + 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)) + { + if (!flag_diagnostics_show_caret) + error_at (loc, + "called object %qE is not a function or function pointer", + function); + else if (DECL_P (function)) + { + error_at (loc, + "called object %qD is not a function or function pointer", + function); + inform_declaration (function); + } + else + error_at (loc, + "called object is not a function or function pointer"); + return error_mark_node; + } + + if (fundecl && TREE_THIS_VOLATILE (fundecl)) + current_function_returns_abnormally = 1; + + /* 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. */ + + nargs = convert_arguments (TYPE_ARG_TYPES (fntype), params, origtypes, + function, fundecl); + if (nargs < 0) + return error_mark_node; + + /* Check that the function is called through a compatible prototype. + If it is not, replace the call by a trap, wrapped up in a compound + expression if necessary. This has the nice side-effect to prevent + the tree-inliner from generating invalid assignment trees which may + blow up in the RTL expander later. */ + if (CONVERT_EXPR_P (function) + && TREE_CODE (tem = TREE_OPERAND (function, 0)) == ADDR_EXPR + && TREE_CODE (tem = TREE_OPERAND (tem, 0)) == FUNCTION_DECL + && !comptypes (fntype, TREE_TYPE (tem))) + { + tree return_type = TREE_TYPE (fntype); + tree trap = build_function_call (loc, + builtin_decl_explicit (BUILT_IN_TRAP), + NULL_TREE); + int i; + + /* This situation leads to run-time undefined behavior. We can't, + therefore, simply error unless we can prove that all possible + executions of the program must execute the code. */ + if (warning_at (loc, 0, "function called through a non-compatible type")) + /* We can, however, treat "undefined" any way we please. + Call abort to encourage the user to fix the program. */ + inform (loc, "if this code is reached, the program will abort"); + /* Before the abort, allow the function arguments to exit or + call longjmp. */ + for (i = 0; i < nargs; i++) + trap = build2 (COMPOUND_EXPR, void_type_node, + VEC_index (tree, params, i), trap); + + if (VOID_TYPE_P (return_type)) + { + if (TYPE_QUALS (return_type) != TYPE_UNQUALIFIED) + pedwarn (loc, 0, + "function with qualified void return type called"); + return trap; + } + else + { + tree rhs; + + if (AGGREGATE_TYPE_P (return_type)) + rhs = build_compound_literal (loc, return_type, + build_constructor (return_type, 0), + false); + else + rhs = build_zero_cst (return_type); + + return require_complete_type (build2 (COMPOUND_EXPR, return_type, + trap, rhs)); + } + } + + argarray = VEC_address (tree, params); + + /* Check that arguments to builtin functions match the expectations. */ + if (fundecl + && DECL_BUILT_IN (fundecl) + && DECL_BUILT_IN_CLASS (fundecl) == BUILT_IN_NORMAL + && !check_builtin_function_arguments (fundecl, nargs, argarray)) + return error_mark_node; + + /* Check that the arguments to the function are valid. */ + check_function_arguments (fntype, nargs, argarray); + + if (name != NULL_TREE + && !strncmp (IDENTIFIER_POINTER (name), "__builtin_", 10)) + { + if (require_constant_value) + result = + fold_build_call_array_initializer_loc (loc, TREE_TYPE (fntype), + function, nargs, argarray); + else + result = fold_build_call_array_loc (loc, TREE_TYPE (fntype), + function, nargs, argarray); + if (TREE_CODE (result) == NOP_EXPR + && TREE_CODE (TREE_OPERAND (result, 0)) == INTEGER_CST) + STRIP_TYPE_NOPS (result); + } + else + result = build_call_array_loc (loc, TREE_TYPE (fntype), + function, nargs, argarray); + + if (VOID_TYPE_P (TREE_TYPE (result))) + { + if (TYPE_QUALS (TREE_TYPE (result)) != TYPE_UNQUALIFIED) + pedwarn (loc, 0, + "function with qualified void return type called"); + return result; + } + return require_complete_type (result); +} + +/* Convert the argument expressions in the vector VALUES + to the types in the list TYPELIST. + + If TYPELIST is exhausted, or when an element has NULL as its type, + perform the default conversions. + + ORIGTYPES is the original types of the expressions in VALUES. This + holds the type of enum values which have been converted to integral + types. It may be NULL. + + FUNCTION is a tree for the called function. It is used only for + error messages, where it is formatted with %qE. + + This is also where warnings about wrong number of args are generated. + + Returns the actual number of arguments processed (which may be less + than the length of VALUES in some error situations), or -1 on + failure. */ + +static int +convert_arguments (tree typelist, VEC(tree,gc) *values, + VEC(tree,gc) *origtypes, tree function, tree fundecl) +{ + tree typetail, val; + unsigned int parmnum; + bool error_args = false; + const bool type_generic = fundecl + && lookup_attribute ("type generic", TYPE_ATTRIBUTES(TREE_TYPE (fundecl))); + bool type_generic_remove_excess_precision = false; + tree selector; + + /* Change pointer to function to the function itself for + diagnostics. */ + if (TREE_CODE (function) == ADDR_EXPR + && TREE_CODE (TREE_OPERAND (function, 0)) == FUNCTION_DECL) + function = TREE_OPERAND (function, 0); + + /* Handle an ObjC selector specially for diagnostics. */ + selector = objc_message_selector (); + + /* For type-generic built-in functions, determine whether excess + precision should be removed (classification) or not + (comparison). */ + if (type_generic + && DECL_BUILT_IN (fundecl) + && DECL_BUILT_IN_CLASS (fundecl) == BUILT_IN_NORMAL) + { + switch (DECL_FUNCTION_CODE (fundecl)) + { + case BUILT_IN_ISFINITE: + case BUILT_IN_ISINF: + case BUILT_IN_ISINF_SIGN: + case BUILT_IN_ISNAN: + case BUILT_IN_ISNORMAL: + case BUILT_IN_FPCLASSIFY: + type_generic_remove_excess_precision = true; + break; + + default: + type_generic_remove_excess_precision = false; + break; + } + } + + /* Scan the given expressions and types, producing individual + converted arguments. */ + + for (typetail = typelist, parmnum = 0; + VEC_iterate (tree, values, parmnum, val); + ++parmnum) + { + tree type = typetail ? TREE_VALUE (typetail) : 0; + tree valtype = TREE_TYPE (val); + tree rname = function; + int argnum = parmnum + 1; + const char *invalid_func_diag; + bool excess_precision = false; + bool npc; + tree parmval; + + if (type == void_type_node) + { + if (selector) + error_at (input_location, + "too many arguments to method %qE", selector); + else + error_at (input_location, + "too many arguments to function %qE", function); + inform_declaration (fundecl); + return parmnum; + } + + if (selector && argnum > 2) + { + rname = selector; + argnum -= 2; + } + + npc = null_pointer_constant_p (val); + + /* If there is excess precision and a prototype, convert once to + the required type rather than converting via the semantic + type. Likewise without a prototype a float value represented + as long double should be converted once to double. But for + type-generic classification functions excess precision must + be removed here. */ + if (TREE_CODE (val) == EXCESS_PRECISION_EXPR + && (type || !type_generic || !type_generic_remove_excess_precision)) + { + val = TREE_OPERAND (val, 0); + excess_precision = true; + } + val = c_fully_fold (val, false, NULL); + STRIP_TYPE_NOPS (val); + + val = require_complete_type (val); + + if (type != 0) + { + /* Formal parm type is specified by a function prototype. */ + + if (type == error_mark_node || !COMPLETE_TYPE_P (type)) + { + error ("type of formal parameter %d is incomplete", parmnum + 1); + parmval = val; + } + else + { + tree origtype; + + /* Optionally warn about conversions that + differ from the default conversions. */ + if (warn_traditional_conversion || warn_traditional) + { + unsigned int formal_prec = TYPE_PRECISION (type); + + if (INTEGRAL_TYPE_P (type) + && TREE_CODE (valtype) == REAL_TYPE) + warning (0, "passing argument %d of %qE as integer " + "rather than floating due to prototype", + argnum, rname); + if (INTEGRAL_TYPE_P (type) + && TREE_CODE (valtype) == COMPLEX_TYPE) + warning (0, "passing argument %d of %qE as integer " + "rather than complex due to prototype", + argnum, rname); + else if (TREE_CODE (type) == COMPLEX_TYPE + && TREE_CODE (valtype) == REAL_TYPE) + warning (0, "passing argument %d of %qE as complex " + "rather than floating due to prototype", + argnum, rname); + else if (TREE_CODE (type) == REAL_TYPE + && INTEGRAL_TYPE_P (valtype)) + warning (0, "passing argument %d of %qE as floating " + "rather than integer due to prototype", + argnum, rname); + else if (TREE_CODE (type) == COMPLEX_TYPE + && INTEGRAL_TYPE_P (valtype)) + warning (0, "passing argument %d of %qE as complex " + "rather than integer due to prototype", + argnum, rname); + else if (TREE_CODE (type) == REAL_TYPE + && TREE_CODE (valtype) == COMPLEX_TYPE) + warning (0, "passing argument %d of %qE as floating " + "rather than complex due to prototype", + argnum, rname); + /* ??? 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 (valtype) == 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) + && type != dfloat32_type_node) + warning (0, "passing argument %d of %qE as %<float%> " + "rather than %<double%> due to prototype", + argnum, rname); + + /* Warn if mismatch between argument and prototype + for decimal float types. Warn of conversions with + binary float types and of precision narrowing due to + prototype. */ + else if (type != valtype + && (type == dfloat32_type_node + || type == dfloat64_type_node + || type == dfloat128_type_node + || valtype == dfloat32_type_node + || valtype == dfloat64_type_node + || valtype == dfloat128_type_node) + && (formal_prec + <= TYPE_PRECISION (valtype) + || (type == dfloat128_type_node + && (valtype + != dfloat64_type_node + && (valtype + != dfloat32_type_node))) + || (type == dfloat64_type_node + && (valtype + != dfloat32_type_node)))) + warning (0, "passing argument %d of %qE as %qT " + "rather than %qT due to prototype", + argnum, rname, type, valtype); + + } + /* Detect integer changing in width or signedness. + These warnings are only activated with + -Wtraditional-conversion, not with -Wtraditional. */ + else if (warn_traditional_conversion && INTEGRAL_TYPE_P (type) + && INTEGRAL_TYPE_P (valtype)) + { + tree would_have_been = default_conversion (val); + tree type1 = TREE_TYPE (would_have_been); + + if (TREE_CODE (type) == ENUMERAL_TYPE + && (TYPE_MAIN_VARIANT (type) + == TYPE_MAIN_VARIANT (valtype))) + /* No warning if function asks for enum + and the actual arg is that enum type. */ + ; + else if (formal_prec != TYPE_PRECISION (type1)) + warning (OPT_Wtraditional_conversion, + "passing argument %d of %qE " + "with different width due to prototype", + argnum, rname); + else if (TYPE_UNSIGNED (type) == TYPE_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. */ + ; + /* 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 (valtype) < TYPE_PRECISION (type) + && TYPE_UNSIGNED (valtype)) + ; + else if (TYPE_UNSIGNED (type)) + warning (OPT_Wtraditional_conversion, + "passing argument %d of %qE " + "as unsigned due to prototype", + argnum, rname); + else + warning (OPT_Wtraditional_conversion, + "passing argument %d of %qE " + "as signed due to prototype", argnum, rname); + } + } + + /* Possibly restore an EXCESS_PRECISION_EXPR for the + sake of better warnings from convert_and_check. */ + if (excess_precision) + val = build1 (EXCESS_PRECISION_EXPR, valtype, val); + origtype = (origtypes == NULL + ? NULL_TREE + : VEC_index (tree, origtypes, parmnum)); + parmval = convert_for_assignment (input_location, type, val, + origtype, ic_argpass, npc, + fundecl, function, + parmnum + 1); + + if (targetm.calls.promote_prototypes (fundecl ? TREE_TYPE (fundecl) : 0) + && INTEGRAL_TYPE_P (type) + && (TYPE_PRECISION (type) < TYPE_PRECISION (integer_type_node))) + parmval = default_conversion (parmval); + } + } + else if (TREE_CODE (valtype) == REAL_TYPE + && (TYPE_PRECISION (valtype) + < TYPE_PRECISION (double_type_node)) + && !DECIMAL_FLOAT_MODE_P (TYPE_MODE (valtype))) + { + if (type_generic) + parmval = val; + else + { + /* Convert `float' to `double'. */ + if (warn_double_promotion && !c_inhibit_evaluation_warnings) + warning (OPT_Wdouble_promotion, + "implicit conversion from %qT to %qT when passing " + "argument to function", + valtype, double_type_node); + parmval = convert (double_type_node, val); + } + } + else if (excess_precision && !type_generic) + /* A "double" argument with excess precision being passed + without a prototype or in variable arguments. */ + parmval = convert (valtype, val); + else if ((invalid_func_diag = + targetm.calls.invalid_arg_for_unprototyped_fn (typelist, fundecl, val))) + { + error (invalid_func_diag); + return -1; + } + else + /* Convert `short' and `char' to full-size `int'. */ + parmval = default_conversion (val); + + VEC_replace (tree, values, parmnum, parmval); + if (parmval == error_mark_node) + error_args = true; + + if (typetail) + typetail = TREE_CHAIN (typetail); + } + + gcc_assert (parmnum == VEC_length (tree, values)); + + if (typetail != 0 && TREE_VALUE (typetail) != void_type_node) + { + error_at (input_location, + "too few arguments to function %qE", function); + inform_declaration (fundecl); + return -1; + } + + return error_args ? -1 : (int) parmnum; +} + +/* This is the entry point used by the parser to build unary operators + in the input. CODE, a tree_code, specifies the unary operator, and + ARG is the operand. For unary plus, the C parser currently uses + CONVERT_EXPR for code. + + LOC is the location to use for the tree generated. +*/ + +struct c_expr +parser_build_unary_op (location_t loc, enum tree_code code, struct c_expr arg) +{ + struct c_expr result; + + result.value = build_unary_op (loc, code, arg.value, 0); + result.original_code = code; + result.original_type = NULL; + + if (TREE_OVERFLOW_P (result.value) && !TREE_OVERFLOW_P (arg.value)) + overflow_warning (loc, result.value); + + return result; +} + +/* This is the entry point used by the parser to build binary operators + in the input. CODE, a tree_code, specifies the binary operator, and + ARG1 and ARG2 are the operands. 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. + + LOCATION is the location of the binary operator. */ + +struct c_expr +parser_build_binary_op (location_t location, enum tree_code code, + struct c_expr arg1, struct c_expr arg2) +{ + struct c_expr result; + + enum tree_code code1 = arg1.original_code; + enum tree_code code2 = arg2.original_code; + tree type1 = (arg1.original_type + ? arg1.original_type + : TREE_TYPE (arg1.value)); + tree type2 = (arg2.original_type + ? arg2.original_type + : TREE_TYPE (arg2.value)); + + result.value = build_binary_op (location, code, + arg1.value, arg2.value, 1); + result.original_code = code; + result.original_type = NULL; + + if (TREE_CODE (result.value) == ERROR_MARK) + return result; + + if (location != UNKNOWN_LOCATION) + protected_set_expr_location (result.value, location); + + /* Check for cases such as x+y<<z which users are likely + to misinterpret. */ + if (warn_parentheses) + warn_about_parentheses (code, code1, arg1.value, code2, arg2.value); + + if (warn_logical_op) + warn_logical_operator (input_location, code, TREE_TYPE (result.value), + code1, arg1.value, code2, arg2.value); + + /* Warn about comparisons against string literals, with the exception + of testing for equality or inequality of a string literal with NULL. */ + if (code == EQ_EXPR || code == NE_EXPR) + { + if ((code1 == STRING_CST && !integer_zerop (arg2.value)) + || (code2 == STRING_CST && !integer_zerop (arg1.value))) + warning_at (location, OPT_Waddress, + "comparison with string literal results in unspecified behavior"); + } + else if (TREE_CODE_CLASS (code) == tcc_comparison + && (code1 == STRING_CST || code2 == STRING_CST)) + warning_at (location, OPT_Waddress, + "comparison with string literal results in unspecified behavior"); + + if (TREE_OVERFLOW_P (result.value) + && !TREE_OVERFLOW_P (arg1.value) + && !TREE_OVERFLOW_P (arg2.value)) + overflow_warning (location, result.value); + + /* Warn about comparisons of different enum types. */ + if (warn_enum_compare + && TREE_CODE_CLASS (code) == tcc_comparison + && TREE_CODE (type1) == ENUMERAL_TYPE + && TREE_CODE (type2) == ENUMERAL_TYPE + && TYPE_MAIN_VARIANT (type1) != TYPE_MAIN_VARIANT (type2)) + warning_at (location, OPT_Wenum_compare, + "comparison between %qT and %qT", + type1, type2); + + return result; +} + +/* Return a tree for the difference of pointers OP0 and OP1. + The resulting tree has type int. */ + +static tree +pointer_diff (location_t loc, tree op0, tree op1) +{ + tree restype = ptrdiff_type_node; + tree result, inttype; + + addr_space_t as0 = TYPE_ADDR_SPACE (TREE_TYPE (TREE_TYPE (op0))); + addr_space_t as1 = TYPE_ADDR_SPACE (TREE_TYPE (TREE_TYPE (op1))); + tree target_type = TREE_TYPE (TREE_TYPE (op0)); + tree con0, con1, lit0, lit1; + tree orig_op1 = op1; + + /* If the operands point into different address spaces, we need to + explicitly convert them to pointers into the common address space + before we can subtract the numerical address values. */ + if (as0 != as1) + { + addr_space_t as_common; + tree common_type; + + /* Determine the common superset address space. This is guaranteed + to exist because the caller verified that comp_target_types + returned non-zero. */ + if (!addr_space_superset (as0, as1, &as_common)) + gcc_unreachable (); + + common_type = common_pointer_type (TREE_TYPE (op0), TREE_TYPE (op1)); + op0 = convert (common_type, op0); + op1 = convert (common_type, op1); + } + + /* Determine integer type to perform computations in. This will usually + be the same as the result type (ptrdiff_t), but may need to be a wider + type if pointers for the address space are wider than ptrdiff_t. */ + if (TYPE_PRECISION (restype) < TYPE_PRECISION (TREE_TYPE (op0))) + inttype = c_common_type_for_size (TYPE_PRECISION (TREE_TYPE (op0)), 0); + else + inttype = restype; + + + if (TREE_CODE (target_type) == VOID_TYPE) + pedwarn (loc, pedantic ? OPT_Wpedantic : OPT_Wpointer_arith, + "pointer of type %<void *%> used in subtraction"); + if (TREE_CODE (target_type) == FUNCTION_TYPE) + pedwarn (loc, pedantic ? OPT_Wpedantic : OPT_Wpointer_arith, + "pointer to a function used in subtraction"); + + /* If the conversion to ptrdiff_type does anything like widening or + converting a partial to an integral mode, we get a convert_expression + that is in the way to do any simplifications. + (fold-const.c doesn't know that the extra bits won't be needed. + split_tree uses STRIP_SIGN_NOPS, which leaves conversions to a + different mode in place.) + So first try to find a common term here 'by hand'; we want to cover + at least the cases that occur in legal static initializers. */ + if (CONVERT_EXPR_P (op0) + && (TYPE_PRECISION (TREE_TYPE (op0)) + == TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (op0, 0))))) + con0 = TREE_OPERAND (op0, 0); + else + con0 = op0; + if (CONVERT_EXPR_P (op1) + && (TYPE_PRECISION (TREE_TYPE (op1)) + == TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (op1, 0))))) + con1 = TREE_OPERAND (op1, 0); + else + con1 = op1; + + if (TREE_CODE (con0) == POINTER_PLUS_EXPR) + { + lit0 = TREE_OPERAND (con0, 1); + con0 = TREE_OPERAND (con0, 0); + } + else + lit0 = integer_zero_node; + + if (TREE_CODE (con1) == POINTER_PLUS_EXPR) + { + lit1 = TREE_OPERAND (con1, 1); + con1 = TREE_OPERAND (con1, 0); + } + else + lit1 = integer_zero_node; + + if (operand_equal_p (con0, con1, 0)) + { + op0 = lit0; + op1 = lit1; + } + + + /* 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 (loc, + MINUS_EXPR, convert (inttype, op0), + convert (inttype, op1), 0); + /* This generates an error if op1 is pointer to incomplete type. */ + if (!COMPLETE_OR_VOID_TYPE_P (TREE_TYPE (TREE_TYPE (orig_op1)))) + error_at (loc, "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 = fold_build2_loc (loc, EXACT_DIV_EXPR, inttype, + op0, convert (inttype, op1)); + + /* Convert to final result type if necessary. */ + return convert (restype, result); +} + +/* Construct and perhaps optimize a tree representation + for a unary operation. CODE, a tree_code, specifies the operation + and XARG is the operand. + For any CODE other than ADDR_EXPR, FLAG nonzero suppresses + the default promotions (such as from short to int). + For ADDR_EXPR, the default promotions are not applied; FLAG nonzero + allows non-lvalues; this is only used to handle conversion of non-lvalue + arrays to pointers in C99. + + LOCATION is the location of the operator. */ + +tree +build_unary_op (location_t location, + enum tree_code code, tree xarg, int flag) +{ + /* No default_conversion here. It causes trouble for ADDR_EXPR. */ + tree arg = xarg; + tree argtype = 0; + enum tree_code typecode; + tree val; + tree ret = error_mark_node; + tree eptype = NULL_TREE; + int noconvert = flag; + const char *invalid_op_diag; + bool int_operands; + + int_operands = EXPR_INT_CONST_OPERANDS (xarg); + if (int_operands) + arg = remove_c_maybe_const_expr (arg); + + if (code != ADDR_EXPR) + arg = require_complete_type (arg); + + typecode = TREE_CODE (TREE_TYPE (arg)); + if (typecode == ERROR_MARK) + return error_mark_node; + if (typecode == ENUMERAL_TYPE || typecode == BOOLEAN_TYPE) + typecode = INTEGER_TYPE; + + if ((invalid_op_diag + = targetm.invalid_unary_op (code, TREE_TYPE (xarg)))) + { + error_at (location, invalid_op_diag); + return error_mark_node; + } + + if (TREE_CODE (arg) == EXCESS_PRECISION_EXPR) + { + eptype = TREE_TYPE (arg); + arg = TREE_OPERAND (arg, 0); + } + + 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 == FIXED_POINT_TYPE || typecode == COMPLEX_TYPE + || typecode == VECTOR_TYPE)) + { + error_at (location, "wrong type argument to unary plus"); + return error_mark_node; + } + else if (!noconvert) + arg = default_conversion (arg); + arg = non_lvalue_loc (location, arg); + break; + + case NEGATE_EXPR: + if (!(typecode == INTEGER_TYPE || typecode == REAL_TYPE + || typecode == FIXED_POINT_TYPE || typecode == COMPLEX_TYPE + || typecode == VECTOR_TYPE)) + { + error_at (location, "wrong type argument to unary minus"); + return error_mark_node; + } + else if (!noconvert) + arg = default_conversion (arg); + break; + + case BIT_NOT_EXPR: + /* ~ works on integer types and non float vectors. */ + if (typecode == INTEGER_TYPE + || (typecode == VECTOR_TYPE + && !VECTOR_FLOAT_TYPE_P (TREE_TYPE (arg)))) + { + if (!noconvert) + arg = default_conversion (arg); + } + else if (typecode == COMPLEX_TYPE) + { + code = CONJ_EXPR; + pedwarn (location, OPT_Wpedantic, + "ISO C does not support %<~%> for complex conjugation"); + if (!noconvert) + arg = default_conversion (arg); + } + else + { + error_at (location, "wrong type argument to bit-complement"); + return error_mark_node; + } + break; + + case ABS_EXPR: + if (!(typecode == INTEGER_TYPE || typecode == REAL_TYPE)) + { + error_at (location, "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_at (location, "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 != FIXED_POINT_TYPE + && typecode != REAL_TYPE && typecode != POINTER_TYPE + && typecode != COMPLEX_TYPE) + { + error_at (location, + "wrong type argument to unary exclamation mark"); + return error_mark_node; + } + arg = c_objc_common_truthvalue_conversion (location, arg); + ret = invert_truthvalue_loc (location, arg); + /* If the TRUTH_NOT_EXPR has been folded, reset the location. */ + if (EXPR_P (ret) && EXPR_HAS_LOCATION (ret)) + location = EXPR_LOCATION (ret); + goto return_build_unary_op; + + case REALPART_EXPR: + case IMAGPART_EXPR: + ret = build_real_imag_expr (location, code, arg); + if (ret == error_mark_node) + return error_mark_node; + if (eptype && TREE_CODE (eptype) == COMPLEX_TYPE) + eptype = TREE_TYPE (eptype); + goto return_build_unary_op; + + case PREINCREMENT_EXPR: + case POSTINCREMENT_EXPR: + case PREDECREMENT_EXPR: + case POSTDECREMENT_EXPR: + + if (TREE_CODE (arg) == C_MAYBE_CONST_EXPR) + { + tree inner = build_unary_op (location, code, + C_MAYBE_CONST_EXPR_EXPR (arg), flag); + if (inner == error_mark_node) + return error_mark_node; + ret = build2 (C_MAYBE_CONST_EXPR, TREE_TYPE (inner), + C_MAYBE_CONST_EXPR_PRE (arg), inner); + gcc_assert (!C_MAYBE_CONST_EXPR_INT_OPERANDS (arg)); + C_MAYBE_CONST_EXPR_NON_CONST (ret) = 1; + goto return_build_unary_op; + } + + /* Complain about anything that is not a true lvalue. In + Objective-C, skip this check for property_refs. */ + if (!objc_is_property_ref (arg) + && !lvalue_or_else (location, + arg, ((code == PREINCREMENT_EXPR + || code == POSTINCREMENT_EXPR) + ? lv_increment + : lv_decrement))) + return error_mark_node; + + if (warn_cxx_compat && TREE_CODE (TREE_TYPE (arg)) == ENUMERAL_TYPE) + { + if (code == PREINCREMENT_EXPR || code == POSTINCREMENT_EXPR) + warning_at (location, OPT_Wc___compat, + "increment of enumeration value is invalid in C++"); + else + warning_at (location, OPT_Wc___compat, + "decrement of enumeration value is invalid in C++"); + } + + /* Ensure the argument is fully folded inside any SAVE_EXPR. */ + arg = c_fully_fold (arg, false, NULL); + + /* Increment or decrement the real part of the value, + and don't change the imaginary part. */ + if (typecode == COMPLEX_TYPE) + { + tree real, imag; + + pedwarn (location, OPT_Wpedantic, + "ISO C does not support %<++%> and %<--%> on complex types"); + + arg = stabilize_reference (arg); + real = build_unary_op (EXPR_LOCATION (arg), REALPART_EXPR, arg, 1); + imag = build_unary_op (EXPR_LOCATION (arg), IMAGPART_EXPR, arg, 1); + real = build_unary_op (EXPR_LOCATION (arg), code, real, 1); + if (real == error_mark_node || imag == error_mark_node) + return error_mark_node; + ret = build2 (COMPLEX_EXPR, TREE_TYPE (arg), + real, imag); + goto return_build_unary_op; + } + + /* Report invalid types. */ + + if (typecode != POINTER_TYPE && typecode != FIXED_POINT_TYPE + && typecode != INTEGER_TYPE && typecode != REAL_TYPE) + { + if (code == PREINCREMENT_EXPR || code == POSTINCREMENT_EXPR) + error_at (location, "wrong type argument to increment"); + else + error_at (location, "wrong type argument to decrement"); + + return error_mark_node; + } + + { + tree inc; + + 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 (!COMPLETE_OR_VOID_TYPE_P (TREE_TYPE (argtype))) + { + if (code == PREINCREMENT_EXPR || code == POSTINCREMENT_EXPR) + error_at (location, + "increment of pointer to unknown structure"); + else + error_at (location, + "decrement of pointer to unknown structure"); + } + else if (TREE_CODE (TREE_TYPE (argtype)) == FUNCTION_TYPE + || TREE_CODE (TREE_TYPE (argtype)) == VOID_TYPE) + { + if (code == PREINCREMENT_EXPR || code == POSTINCREMENT_EXPR) + pedwarn (location, pedantic ? OPT_Wpedantic : OPT_Wpointer_arith, + "wrong type argument to increment"); + else + pedwarn (location, pedantic ? OPT_Wpedantic : OPT_Wpointer_arith, + "wrong type argument to decrement"); + } + + inc = c_size_in_bytes (TREE_TYPE (argtype)); + inc = convert_to_ptrofftype_loc (location, inc); + } + else if (FRACT_MODE_P (TYPE_MODE (argtype))) + { + /* For signed fract types, we invert ++ to -- or + -- to ++, and change inc from 1 to -1, because + it is not possible to represent 1 in signed fract constants. + For unsigned fract types, the result always overflows and + we get an undefined (original) or the maximum value. */ + if (code == PREINCREMENT_EXPR) + code = PREDECREMENT_EXPR; + else if (code == PREDECREMENT_EXPR) + code = PREINCREMENT_EXPR; + else if (code == POSTINCREMENT_EXPR) + code = POSTDECREMENT_EXPR; + else /* code == POSTDECREMENT_EXPR */ + code = POSTINCREMENT_EXPR; + + inc = integer_minus_one_node; + inc = convert (argtype, inc); + } + else + { + inc = integer_one_node; + inc = convert (argtype, inc); + } + + /* If 'arg' is an Objective-C PROPERTY_REF expression, then we + need to ask Objective-C to build the increment or decrement + expression for it. */ + if (objc_is_property_ref (arg)) + return objc_build_incr_expr_for_property_ref (location, code, + arg, inc); + + /* Report a read-only lvalue. */ + if (TYPE_READONLY (argtype)) + { + readonly_error (arg, + ((code == PREINCREMENT_EXPR + || code == POSTINCREMENT_EXPR) + ? lv_increment : lv_decrement)); + return error_mark_node; + } + else if (TREE_READONLY (arg)) + readonly_warning (arg, + ((code == PREINCREMENT_EXPR + || code == POSTINCREMENT_EXPR) + ? lv_increment : lv_decrement)); + + if (TREE_CODE (TREE_TYPE (arg)) == BOOLEAN_TYPE) + val = boolean_increment (code, arg); + else + val = build2 (code, TREE_TYPE (arg), arg, inc); + TREE_SIDE_EFFECTS (val) = 1; + if (TREE_CODE (val) != code) + TREE_NO_WARNING (val) = 1; + ret = val; + goto return_build_unary_op; + } + + case ADDR_EXPR: + /* Note that this operation never does default_conversion. */ + + /* The operand of unary '&' must be an lvalue (which excludes + expressions of type void), or, in C99, the result of a [] or + unary '*' operator. */ + if (VOID_TYPE_P (TREE_TYPE (arg)) + && TYPE_QUALS (TREE_TYPE (arg)) == TYPE_UNQUALIFIED + && (TREE_CODE (arg) != INDIRECT_REF + || !flag_isoc99)) + pedwarn (location, 0, "taking address of expression of type %<void%>"); + + /* 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_loc (location, TREE_OPERAND (arg, 0)); + ret = TREE_OPERAND (arg, 0); + goto return_build_unary_op; + } + + /* For &x[y], return x+y */ + if (TREE_CODE (arg) == ARRAY_REF) + { + tree op0 = TREE_OPERAND (arg, 0); + if (!c_mark_addressable (op0)) + return error_mark_node; + } + + /* Anything not already handled and not a true memory reference + or a non-lvalue array is an error. */ + else if (typecode != FUNCTION_TYPE && !flag + && !lvalue_or_else (location, arg, lv_addressof)) + return error_mark_node; + + /* Move address operations inside C_MAYBE_CONST_EXPR to simplify + folding later. */ + if (TREE_CODE (arg) == C_MAYBE_CONST_EXPR) + { + tree inner = build_unary_op (location, code, + C_MAYBE_CONST_EXPR_EXPR (arg), flag); + ret = build2 (C_MAYBE_CONST_EXPR, TREE_TYPE (inner), + C_MAYBE_CONST_EXPR_PRE (arg), inner); + gcc_assert (!C_MAYBE_CONST_EXPR_INT_OPERANDS (arg)); + C_MAYBE_CONST_EXPR_NON_CONST (ret) + = C_MAYBE_CONST_EXPR_NON_CONST (arg); + goto return_build_unary_op; + } + + /* 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. This is only needed + for function types. */ + if ((DECL_P (arg) || REFERENCE_CLASS_P (arg)) + && (TREE_READONLY (arg) || TREE_THIS_VOLATILE (arg)) + && TREE_CODE (argtype) == FUNCTION_TYPE) + { + int orig_quals = TYPE_QUALS (strip_array_types (argtype)); + int quals = orig_quals; + + if (TREE_READONLY (arg)) + quals |= TYPE_QUAL_CONST; + if (TREE_THIS_VOLATILE (arg)) + quals |= TYPE_QUAL_VOLATILE; + + argtype = c_build_qualified_type (argtype, quals); + } + + if (!c_mark_addressable (arg)) + return error_mark_node; + + gcc_assert (TREE_CODE (arg) != COMPONENT_REF + || !DECL_C_BIT_FIELD (TREE_OPERAND (arg, 1))); + + argtype = build_pointer_type (argtype); + + /* ??? Cope with user tricks that amount to offsetof. Delete this + when we have proper support for integer constant expressions. */ + val = get_base_address (arg); + if (val && TREE_CODE (val) == INDIRECT_REF + && TREE_CONSTANT (TREE_OPERAND (val, 0))) + { + ret = fold_convert_loc (location, argtype, fold_offsetof_1 (arg)); + goto return_build_unary_op; + } + + val = build1 (ADDR_EXPR, argtype, arg); + + ret = val; + goto return_build_unary_op; + + default: + gcc_unreachable (); + } + + if (argtype == 0) + argtype = TREE_TYPE (arg); + if (TREE_CODE (arg) == INTEGER_CST) + ret = (require_constant_value + ? fold_build1_initializer_loc (location, code, argtype, arg) + : fold_build1_loc (location, code, argtype, arg)); + else + ret = build1 (code, argtype, arg); + return_build_unary_op: + gcc_assert (ret != error_mark_node); + if (TREE_CODE (ret) == INTEGER_CST && !TREE_OVERFLOW (ret) + && !(TREE_CODE (xarg) == INTEGER_CST && !TREE_OVERFLOW (xarg))) + ret = build1 (NOP_EXPR, TREE_TYPE (ret), ret); + else if (TREE_CODE (ret) != INTEGER_CST && int_operands) + ret = note_integer_operands (ret); + if (eptype) + ret = build1 (EXCESS_PRECISION_EXPR, eptype, ret); + protected_set_expr_location (ret, location); + return ret; +} + +/* 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 C_DECL_REGISTER. */ + +bool +lvalue_p (const_tree ref) +{ + const 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 C_MAYBE_CONST_EXPR: + return lvalue_p (TREE_OPERAND (ref, 1)); + + case COMPOUND_LITERAL_EXPR: + 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: + return TREE_CODE (TREE_TYPE (ref)) == ARRAY_TYPE; + + default: + return 0; + } +} + +/* Give a warning for storing in something that is read-only in GCC + terms but not const in ISO C terms. */ + +static void +readonly_warning (tree arg, enum lvalue_use use) +{ + switch (use) + { + case lv_assign: + warning (0, "assignment of read-only location %qE", arg); + break; + case lv_increment: + warning (0, "increment of read-only location %qE", arg); + break; + case lv_decrement: + warning (0, "decrement of read-only location %qE", arg); + break; + default: + gcc_unreachable (); + } + return; +} + + +/* Return nonzero if REF is an lvalue valid for this language; + otherwise, print an error message and return zero. USE says + how the lvalue is being used and so selects the error message. + LOCATION is the location at which any error should be reported. */ + +static int +lvalue_or_else (location_t loc, const_tree ref, enum lvalue_use use) +{ + int win = lvalue_p (ref); + + if (!win) + lvalue_error (loc, use); + + return win; +} + +/* Mark EXP saying that we need to be able to take the + address of it; it should not be allocated in a register. + Returns true if successful. */ + +bool +c_mark_addressable (tree exp) +{ + 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 bit-field %qD", TREE_OPERAND (x, 1)); + return false; + } + + /* ... fall through ... */ + + case ADDR_EXPR: + case ARRAY_REF: + case REALPART_EXPR: + case IMAGPART_EXPR: + x = TREE_OPERAND (x, 0); + break; + + case COMPOUND_LITERAL_EXPR: + case CONSTRUCTOR: + TREE_ADDRESSABLE (x) = 1; + return true; + + case VAR_DECL: + case CONST_DECL: + case PARM_DECL: + case RESULT_DECL: + if (C_DECL_REGISTER (x) + && DECL_NONLOCAL (x)) + { + if (TREE_PUBLIC (x) || TREE_STATIC (x) || DECL_EXTERNAL (x)) + { + error + ("global register variable %qD used in nested function", x); + return false; + } + pedwarn (input_location, 0, "register variable %qD used in nested function", x); + } + else if (C_DECL_REGISTER (x)) + { + if (TREE_PUBLIC (x) || TREE_STATIC (x) || DECL_EXTERNAL (x)) + error ("address of global register variable %qD requested", x); + else + error ("address of register variable %qD requested", x); + return false; + } + + /* drops in */ + case FUNCTION_DECL: + TREE_ADDRESSABLE (x) = 1; + /* drops out */ + default: + return true; + } +} + +/* Convert EXPR to TYPE, warning about conversion problems with + constants. SEMANTIC_TYPE is the type this conversion would use + without excess precision. If SEMANTIC_TYPE is NULL, this function + is equivalent to convert_and_check. This function is a wrapper that + handles conversions that may be different than + the usual ones because of excess precision. */ + +static tree +ep_convert_and_check (tree type, tree expr, tree semantic_type) +{ + if (TREE_TYPE (expr) == type) + return expr; + + if (!semantic_type) + return convert_and_check (type, expr); + + if (TREE_CODE (TREE_TYPE (expr)) == INTEGER_TYPE + && TREE_TYPE (expr) != semantic_type) + { + /* For integers, we need to check the real conversion, not + the conversion to the excess precision type. */ + expr = convert_and_check (semantic_type, expr); + } + /* Result type is the excess precision type, which should be + large enough, so do not check. */ + return convert (type, expr); +} + +/* Build and return a conditional expression IFEXP ? OP1 : OP2. If + IFEXP_BCP then the condition is a call to __builtin_constant_p, and + if folded to an integer constant then the unselected half may + contain arbitrary operations not normally permitted in constant + expressions. Set the location of the expression to LOC. */ + +tree +build_conditional_expr (location_t colon_loc, tree ifexp, bool ifexp_bcp, + tree op1, tree op1_original_type, tree op2, + tree op2_original_type) +{ + tree type1; + tree type2; + enum tree_code code1; + enum tree_code code2; + tree result_type = NULL; + tree semantic_result_type = NULL; + tree orig_op1 = op1, orig_op2 = op2; + bool int_const, op1_int_operands, op2_int_operands, int_operands; + bool ifexp_int_operands; + tree ret; + + op1_int_operands = EXPR_INT_CONST_OPERANDS (orig_op1); + if (op1_int_operands) + op1 = remove_c_maybe_const_expr (op1); + op2_int_operands = EXPR_INT_CONST_OPERANDS (orig_op2); + if (op2_int_operands) + op2 = remove_c_maybe_const_expr (op2); + ifexp_int_operands = EXPR_INT_CONST_OPERANDS (ifexp); + if (ifexp_int_operands) + ifexp = remove_c_maybe_const_expr (ifexp); + + /* 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); + + /* C90 does not permit non-lvalue arrays in conditional expressions. + In C99 they will be pointers by now. */ + if (code1 == ARRAY_TYPE || code2 == ARRAY_TYPE) + { + error_at (colon_loc, "non-lvalue array in conditional expression"); + return error_mark_node; + } + + if ((TREE_CODE (op1) == EXCESS_PRECISION_EXPR + || TREE_CODE (op2) == EXCESS_PRECISION_EXPR) + && (code1 == INTEGER_TYPE || code1 == REAL_TYPE + || code1 == COMPLEX_TYPE) + && (code2 == INTEGER_TYPE || code2 == REAL_TYPE + || code2 == COMPLEX_TYPE)) + { + semantic_result_type = c_common_type (type1, type2); + if (TREE_CODE (op1) == EXCESS_PRECISION_EXPR) + { + op1 = TREE_OPERAND (op1, 0); + type1 = TREE_TYPE (op1); + gcc_assert (TREE_CODE (type1) == code1); + } + if (TREE_CODE (op2) == EXCESS_PRECISION_EXPR) + { + op2 = TREE_OPERAND (op2, 0); + type2 = TREE_TYPE (op2); + gcc_assert (TREE_CODE (type2) == code2); + } + } + + if (warn_cxx_compat) + { + tree t1 = op1_original_type ? op1_original_type : TREE_TYPE (orig_op1); + tree t2 = op2_original_type ? op2_original_type : TREE_TYPE (orig_op2); + + if (TREE_CODE (t1) == ENUMERAL_TYPE + && TREE_CODE (t2) == ENUMERAL_TYPE + && TYPE_MAIN_VARIANT (t1) != TYPE_MAIN_VARIANT (t2)) + warning_at (colon_loc, OPT_Wc___compat, + ("different enum types in conditional is " + "invalid in C++: %qT vs %qT"), + t1, t2); + } + + /* 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 + || code1 == COMPLEX_TYPE) + && (code2 == INTEGER_TYPE || code2 == REAL_TYPE + || code2 == COMPLEX_TYPE)) + { + result_type = c_common_type (type1, type2); + do_warn_double_promotion (result_type, type1, type2, + "implicit conversion from %qT to %qT to " + "match other result of conditional", + colon_loc); + + /* If -Wsign-compare, warn here if type1 and type2 have + different signedness. We'll promote the signed to unsigned + and later code won't know it used to be different. + Do this check on the original types, so that explicit casts + will be considered, but default promotions won't. */ + if (c_inhibit_evaluation_warnings == 0) + { + int unsigned_op1 = TYPE_UNSIGNED (TREE_TYPE (orig_op1)); + int unsigned_op2 = TYPE_UNSIGNED (TREE_TYPE (orig_op2)); + + if (unsigned_op1 ^ unsigned_op2) + { + bool ovf; + + /* Do not warn if the result type is signed, since the + signed type will only be chosen if it can represent + all the values of the unsigned type. */ + if (!TYPE_UNSIGNED (result_type)) + /* OK */; + else + { + bool op1_maybe_const = true; + bool op2_maybe_const = true; + + /* 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. This warning requires the + operands to be folded for best results, so do + that folding in this case even without + warn_sign_compare to avoid warning options + possibly affecting code generation. */ + c_inhibit_evaluation_warnings + += (ifexp == truthvalue_false_node); + op1 = c_fully_fold (op1, require_constant_value, + &op1_maybe_const); + c_inhibit_evaluation_warnings + -= (ifexp == truthvalue_false_node); + + c_inhibit_evaluation_warnings + += (ifexp == truthvalue_true_node); + op2 = c_fully_fold (op2, require_constant_value, + &op2_maybe_const); + c_inhibit_evaluation_warnings + -= (ifexp == truthvalue_true_node); + + if (warn_sign_compare) + { + if ((unsigned_op2 + && tree_expr_nonnegative_warnv_p (op1, &ovf)) + || (unsigned_op1 + && tree_expr_nonnegative_warnv_p (op2, &ovf))) + /* OK */; + else + warning_at (colon_loc, OPT_Wsign_compare, + ("signed and unsigned type in " + "conditional expression")); + } + if (!op1_maybe_const || TREE_CODE (op1) != INTEGER_CST) + op1 = c_wrap_maybe_const (op1, !op1_maybe_const); + if (!op2_maybe_const || TREE_CODE (op2) != INTEGER_CST) + op2 = c_wrap_maybe_const (op2, !op2_maybe_const); + } + } + } + } + else if (code1 == VOID_TYPE || code2 == VOID_TYPE) + { + if (code1 != VOID_TYPE || code2 != VOID_TYPE) + pedwarn (colon_loc, OPT_Wpedantic, + "ISO C forbids conditional expr with only one void side"); + result_type = void_type_node; + } + else if (code1 == POINTER_TYPE && code2 == POINTER_TYPE) + { + addr_space_t as1 = TYPE_ADDR_SPACE (TREE_TYPE (type1)); + addr_space_t as2 = TYPE_ADDR_SPACE (TREE_TYPE (type2)); + addr_space_t as_common; + + if (comp_target_types (colon_loc, type1, type2)) + result_type = common_pointer_type (type1, type2); + else if (null_pointer_constant_p (orig_op1)) + result_type = type2; + else if (null_pointer_constant_p (orig_op2)) + result_type = type1; + else if (!addr_space_superset (as1, as2, &as_common)) + { + error_at (colon_loc, "pointers to disjoint address spaces " + "used in conditional expression"); + return error_mark_node; + } + else if (VOID_TYPE_P (TREE_TYPE (type1))) + { + if (TREE_CODE (TREE_TYPE (type2)) == FUNCTION_TYPE) + pedwarn (colon_loc, OPT_Wpedantic, + "ISO C forbids conditional expr between " + "%<void *%> and function pointer"); + result_type = build_pointer_type (qualify_type (TREE_TYPE (type1), + TREE_TYPE (type2))); + } + else if (VOID_TYPE_P (TREE_TYPE (type2))) + { + if (TREE_CODE (TREE_TYPE (type1)) == FUNCTION_TYPE) + pedwarn (colon_loc, OPT_Wpedantic, + "ISO C forbids conditional expr between " + "%<void *%> and function pointer"); + result_type = build_pointer_type (qualify_type (TREE_TYPE (type2), + TREE_TYPE (type1))); + } + /* Objective-C pointer comparisons are a bit more lenient. */ + else if (objc_have_common_type (type1, type2, -3, NULL_TREE)) + result_type = objc_common_type (type1, type2); + else + { + int qual = ENCODE_QUAL_ADDR_SPACE (as_common); + + pedwarn (colon_loc, 0, + "pointer type mismatch in conditional expression"); + result_type = build_pointer_type + (build_qualified_type (void_type_node, qual)); + } + } + else if (code1 == POINTER_TYPE && code2 == INTEGER_TYPE) + { + if (!null_pointer_constant_p (orig_op2)) + pedwarn (colon_loc, 0, + "pointer/integer type mismatch in conditional expression"); + else + { + op2 = null_pointer_node; + } + result_type = type1; + } + else if (code2 == POINTER_TYPE && code1 == INTEGER_TYPE) + { + if (!null_pointer_constant_p (orig_op1)) + pedwarn (colon_loc, 0, + "pointer/integer type mismatch in conditional expression"); + else + { + op1 = null_pointer_node; + } + result_type = type2; + } + + if (!result_type) + { + if (flag_cond_mismatch) + result_type = void_type_node; + else + { + error_at (colon_loc, "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, + TYPE_READONLY (type1) || TYPE_READONLY (type2), + TYPE_VOLATILE (type1) || TYPE_VOLATILE (type2)); + + op1 = ep_convert_and_check (result_type, op1, semantic_result_type); + op2 = ep_convert_and_check (result_type, op2, semantic_result_type); + + if (ifexp_bcp && ifexp == truthvalue_true_node) + { + op2_int_operands = true; + op1 = c_fully_fold (op1, require_constant_value, NULL); + } + if (ifexp_bcp && ifexp == truthvalue_false_node) + { + op1_int_operands = true; + op2 = c_fully_fold (op2, require_constant_value, NULL); + } + int_const = int_operands = (ifexp_int_operands + && op1_int_operands + && op2_int_operands); + if (int_operands) + { + int_const = ((ifexp == truthvalue_true_node + && TREE_CODE (orig_op1) == INTEGER_CST + && !TREE_OVERFLOW (orig_op1)) + || (ifexp == truthvalue_false_node + && TREE_CODE (orig_op2) == INTEGER_CST + && !TREE_OVERFLOW (orig_op2))); + } + if (int_const || (ifexp_bcp && TREE_CODE (ifexp) == INTEGER_CST)) + ret = fold_build3_loc (colon_loc, COND_EXPR, result_type, ifexp, op1, op2); + else + { + if (int_operands) + { + op1 = remove_c_maybe_const_expr (op1); + op2 = remove_c_maybe_const_expr (op2); + } + ret = build3 (COND_EXPR, result_type, ifexp, op1, op2); + if (int_operands) + ret = note_integer_operands (ret); + } + if (semantic_result_type) + ret = build1 (EXCESS_PRECISION_EXPR, semantic_result_type, ret); + + protected_set_expr_location (ret, colon_loc); + return ret; +} + +/* Return a compound expression that performs two expressions and + returns the value of the second of them. + + LOC is the location of the COMPOUND_EXPR. */ + +tree +build_compound_expr (location_t loc, tree expr1, tree expr2) +{ + bool expr1_int_operands, expr2_int_operands; + tree eptype = NULL_TREE; + tree ret; + + expr1_int_operands = EXPR_INT_CONST_OPERANDS (expr1); + if (expr1_int_operands) + expr1 = remove_c_maybe_const_expr (expr1); + expr2_int_operands = EXPR_INT_CONST_OPERANDS (expr2); + if (expr2_int_operands) + expr2 = remove_c_maybe_const_expr (expr2); + + if (TREE_CODE (expr1) == EXCESS_PRECISION_EXPR) + expr1 = TREE_OPERAND (expr1, 0); + if (TREE_CODE (expr2) == EXCESS_PRECISION_EXPR) + { + eptype = TREE_TYPE (expr2); + expr2 = TREE_OPERAND (expr2, 0); + } + + if (!TREE_SIDE_EFFECTS (expr1)) + { + /* The left-hand operand of a comma expression is like an expression + statement: with -Wunused, we should warn if it doesn't have + any side-effects, unless it was explicitly cast to (void). */ + if (warn_unused_value) + { + if (VOID_TYPE_P (TREE_TYPE (expr1)) + && CONVERT_EXPR_P (expr1)) + ; /* (void) a, b */ + else if (VOID_TYPE_P (TREE_TYPE (expr1)) + && TREE_CODE (expr1) == COMPOUND_EXPR + && CONVERT_EXPR_P (TREE_OPERAND (expr1, 1))) + ; /* (void) a, (void) b, c */ + else + warning_at (loc, OPT_Wunused_value, + "left-hand operand of comma expression has no effect"); + } + } + + /* 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_value) + warn_if_unused_value (expr1, loc); + + if (expr2 == error_mark_node) + return error_mark_node; + + ret = build2 (COMPOUND_EXPR, TREE_TYPE (expr2), expr1, expr2); + + if (flag_isoc99 + && expr1_int_operands + && expr2_int_operands) + ret = note_integer_operands (ret); + + if (eptype) + ret = build1 (EXCESS_PRECISION_EXPR, eptype, ret); + + protected_set_expr_location (ret, loc); + return ret; +} + +/* Issue -Wcast-qual warnings when appropriate. TYPE is the type to + which we are casting. OTYPE is the type of the expression being + cast. Both TYPE and OTYPE are pointer types. LOC is the location + of the cast. -Wcast-qual appeared on the command line. Named + address space qualifiers are not handled here, because they result + in different warnings. */ + +static void +handle_warn_cast_qual (location_t loc, tree type, tree otype) +{ + tree in_type = type; + tree in_otype = otype; + int added = 0; + int discarded = 0; + bool is_const; + + /* Check that the qualifiers on IN_TYPE are a superset of the + qualifiers of IN_OTYPE. The outermost level of POINTER_TYPE + nodes is uninteresting and we stop as soon as we hit a + non-POINTER_TYPE node on either type. */ + do + { + in_otype = TREE_TYPE (in_otype); + in_type = TREE_TYPE (in_type); + + /* GNU C allows cv-qualified function types. 'const' means the + function is very pure, 'volatile' means it can't return. We + need to warn when such qualifiers are added, not when they're + taken away. */ + if (TREE_CODE (in_otype) == FUNCTION_TYPE + && TREE_CODE (in_type) == FUNCTION_TYPE) + added |= (TYPE_QUALS_NO_ADDR_SPACE (in_type) + & ~TYPE_QUALS_NO_ADDR_SPACE (in_otype)); + else + discarded |= (TYPE_QUALS_NO_ADDR_SPACE (in_otype) + & ~TYPE_QUALS_NO_ADDR_SPACE (in_type)); + } + while (TREE_CODE (in_type) == POINTER_TYPE + && TREE_CODE (in_otype) == POINTER_TYPE); + + if (added) + warning_at (loc, OPT_Wcast_qual, + "cast adds %q#v qualifier to function type", added); + + if (discarded) + /* There are qualifiers present in IN_OTYPE that are not present + in IN_TYPE. */ + warning_at (loc, OPT_Wcast_qual, + "cast discards %q#v qualifier from pointer target type", + discarded); + + if (added || discarded) + return; + + /* A cast from **T to const **T is unsafe, because it can cause a + const value to be changed with no additional warning. We only + issue this warning if T is the same on both sides, and we only + issue the warning if there are the same number of pointers on + both sides, as otherwise the cast is clearly unsafe anyhow. A + cast is unsafe when a qualifier is added at one level and const + is not present at all outer levels. + + To issue this warning, we check at each level whether the cast + adds new qualifiers not already seen. We don't need to special + case function types, as they won't have the same + TYPE_MAIN_VARIANT. */ + + if (TYPE_MAIN_VARIANT (in_type) != TYPE_MAIN_VARIANT (in_otype)) + return; + if (TREE_CODE (TREE_TYPE (type)) != POINTER_TYPE) + return; + + in_type = type; + in_otype = otype; + is_const = TYPE_READONLY (TREE_TYPE (in_type)); + do + { + in_type = TREE_TYPE (in_type); + in_otype = TREE_TYPE (in_otype); + if ((TYPE_QUALS (in_type) &~ TYPE_QUALS (in_otype)) != 0 + && !is_const) + { + warning_at (loc, OPT_Wcast_qual, + "to be safe all intermediate pointers in cast from " + "%qT to %qT must be %<const%> qualified", + otype, type); + break; + } + if (is_const) + is_const = TYPE_READONLY (in_type); + } + while (TREE_CODE (in_type) == POINTER_TYPE); +} + +/* Build an expression representing a cast to type TYPE of expression EXPR. + LOC is the location of the cast-- typically the open paren of the cast. */ + +tree +build_c_cast (location_t loc, tree type, tree expr) +{ + tree value; + + if (TREE_CODE (expr) == EXCESS_PRECISION_EXPR) + expr = TREE_OPERAND (expr, 0); + + value = expr; + + if (type == error_mark_node || expr == error_mark_node) + return error_mark_node; + + /* The ObjC front-end uses TYPE_MAIN_VARIANT to tie together types differing + only in <protocol> qualifications. But when constructing cast expressions, + the protocols do matter and must be kept around. */ + if (objc_is_object_ptr (type) && objc_is_object_ptr (TREE_TYPE (expr))) + return build1 (NOP_EXPR, type, expr); + + type = TYPE_MAIN_VARIANT (type); + + if (TREE_CODE (type) == ARRAY_TYPE) + { + error_at (loc, "cast specifies array type"); + return error_mark_node; + } + + if (TREE_CODE (type) == FUNCTION_TYPE) + { + error_at (loc, "cast specifies function type"); + return error_mark_node; + } + + if (!VOID_TYPE_P (type)) + { + value = require_complete_type (value); + if (value == error_mark_node) + return error_mark_node; + } + + if (type == TYPE_MAIN_VARIANT (TREE_TYPE (value))) + { + if (TREE_CODE (type) == RECORD_TYPE + || TREE_CODE (type) == UNION_TYPE) + pedwarn (loc, OPT_Wpedantic, + "ISO C forbids casting nonscalar to the same type"); + } + else if (TREE_CODE (type) == UNION_TYPE) + { + tree field; + + for (field = TYPE_FIELDS (type); field; field = DECL_CHAIN (field)) + if (TREE_TYPE (field) != error_mark_node + && comptypes (TYPE_MAIN_VARIANT (TREE_TYPE (field)), + TYPE_MAIN_VARIANT (TREE_TYPE (value)))) + break; + + if (field) + { + tree t; + bool maybe_const = true; + + pedwarn (loc, OPT_Wpedantic, "ISO C forbids casts to union type"); + t = c_fully_fold (value, false, &maybe_const); + t = build_constructor_single (type, field, t); + if (!maybe_const) + t = c_wrap_maybe_const (t, true); + t = digest_init (loc, type, t, + NULL_TREE, false, true, 0); + TREE_CONSTANT (t) = TREE_CONSTANT (value); + return t; + } + error_at (loc, "cast to union type from type not present in union"); + return error_mark_node; + } + else + { + tree otype, ovalue; + + if (type == void_type_node) + { + tree t = build1 (CONVERT_EXPR, type, value); + SET_EXPR_LOCATION (t, loc); + return t; + } + + otype = TREE_TYPE (value); + + /* Optionally warn about potentially worrisome casts. */ + if (warn_cast_qual + && TREE_CODE (type) == POINTER_TYPE + && TREE_CODE (otype) == POINTER_TYPE) + handle_warn_cast_qual (loc, type, otype); + + /* Warn about conversions between pointers to disjoint + address spaces. */ + if (TREE_CODE (type) == POINTER_TYPE + && TREE_CODE (otype) == POINTER_TYPE + && !null_pointer_constant_p (value)) + { + addr_space_t as_to = TYPE_ADDR_SPACE (TREE_TYPE (type)); + addr_space_t as_from = TYPE_ADDR_SPACE (TREE_TYPE (otype)); + addr_space_t as_common; + + if (!addr_space_superset (as_to, as_from, &as_common)) + { + if (ADDR_SPACE_GENERIC_P (as_from)) + warning_at (loc, 0, "cast to %s address space pointer " + "from disjoint generic address space pointer", + c_addr_space_name (as_to)); + + else if (ADDR_SPACE_GENERIC_P (as_to)) + warning_at (loc, 0, "cast to generic address space pointer " + "from disjoint %s address space pointer", + c_addr_space_name (as_from)); + + else + warning_at (loc, 0, "cast to %s address space pointer " + "from disjoint %s address space pointer", + c_addr_space_name (as_to), + c_addr_space_name (as_from)); + } + } + + /* Warn about possible alignment problems. */ + if (STRICT_ALIGNMENT + && 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_at (loc, OPT_Wcast_align, + "cast increases required alignment of target type"); + + if (TREE_CODE (type) == INTEGER_TYPE + && TREE_CODE (otype) == POINTER_TYPE + && TYPE_PRECISION (type) != TYPE_PRECISION (otype)) + /* Unlike conversion of integers to pointers, where the + warning is disabled for converting constants because + of cases such as SIG_*, warn about converting constant + pointers to integers. In some cases it may cause unwanted + sign extension, and a warning is appropriate. */ + warning_at (loc, OPT_Wpointer_to_int_cast, + "cast from pointer to integer of different size"); + + if (TREE_CODE (value) == CALL_EXPR + && TREE_CODE (type) != TREE_CODE (otype)) + warning_at (loc, OPT_Wbad_function_cast, + "cast from function call of type %qT " + "to non-matching type %qT", otype, type); + + if (TREE_CODE (type) == POINTER_TYPE + && TREE_CODE (otype) == INTEGER_TYPE + && TYPE_PRECISION (type) != TYPE_PRECISION (otype) + /* Don't warn about converting any constant. */ + && !TREE_CONSTANT (value)) + warning_at (loc, + OPT_Wint_to_pointer_cast, "cast to pointer from integer " + "of different size"); + + if (warn_strict_aliasing <= 2) + strict_aliasing_warning (otype, type, expr); + + /* If pedantic, warn for conversions between function and object + pointer types, except for converting a null pointer constant + to function pointer type. */ + if (pedantic + && TREE_CODE (type) == POINTER_TYPE + && TREE_CODE (otype) == POINTER_TYPE + && TREE_CODE (TREE_TYPE (otype)) == FUNCTION_TYPE + && TREE_CODE (TREE_TYPE (type)) != FUNCTION_TYPE) + pedwarn (loc, OPT_Wpedantic, "ISO C forbids " + "conversion of function pointer to object pointer type"); + + if (pedantic + && TREE_CODE (type) == POINTER_TYPE + && TREE_CODE (otype) == POINTER_TYPE + && TREE_CODE (TREE_TYPE (type)) == FUNCTION_TYPE + && TREE_CODE (TREE_TYPE (otype)) != FUNCTION_TYPE + && !null_pointer_constant_p (value)) + pedwarn (loc, OPT_Wpedantic, "ISO C forbids " + "conversion of object pointer to function pointer type"); + + ovalue = value; + value = convert (type, value); + + /* Ignore any integer overflow caused by the cast. */ + if (TREE_CODE (value) == INTEGER_CST && !FLOAT_TYPE_P (otype)) + { + if (CONSTANT_CLASS_P (ovalue) && TREE_OVERFLOW (ovalue)) + { + if (!TREE_OVERFLOW (value)) + { + /* Avoid clobbering a shared constant. */ + value = copy_node (value); + TREE_OVERFLOW (value) = TREE_OVERFLOW (ovalue); + } + } + else if (TREE_OVERFLOW (value)) + /* Reset VALUE's overflow flags, ensuring constant sharing. */ + value = build_int_cst_wide (TREE_TYPE (value), + TREE_INT_CST_LOW (value), + TREE_INT_CST_HIGH (value)); + } + } + + /* Don't let a cast be an lvalue. */ + if (value == expr) + value = non_lvalue_loc (loc, value); + + /* Don't allow the results of casting to floating-point or complex + types be confused with actual constants, or casts involving + integer and pointer types other than direct integer-to-integer + and integer-to-pointer be confused with integer constant + expressions and null pointer constants. */ + if (TREE_CODE (value) == REAL_CST + || TREE_CODE (value) == COMPLEX_CST + || (TREE_CODE (value) == INTEGER_CST + && !((TREE_CODE (expr) == INTEGER_CST + && INTEGRAL_TYPE_P (TREE_TYPE (expr))) + || TREE_CODE (expr) == REAL_CST + || TREE_CODE (expr) == COMPLEX_CST))) + value = build1 (NOP_EXPR, type, value); + + if (CAN_HAVE_LOCATION_P (value)) + SET_EXPR_LOCATION (value, loc); + return value; +} + +/* Interpret a cast of expression EXPR to type TYPE. LOC is the + location of the open paren of the cast, or the position of the cast + expr. */ +tree +c_cast_expr (location_t loc, struct c_type_name *type_name, tree expr) +{ + tree type; + tree type_expr = NULL_TREE; + bool type_expr_const = true; + tree ret; + int saved_wsp = warn_strict_prototypes; + + /* This avoids warnings about unprototyped casts on + integers. E.g. "#define SIG_DFL (void(*)())0". */ + if (TREE_CODE (expr) == INTEGER_CST) + warn_strict_prototypes = 0; + type = groktypename (type_name, &type_expr, &type_expr_const); + warn_strict_prototypes = saved_wsp; + + ret = build_c_cast (loc, type, expr); + if (type_expr) + { + ret = build2 (C_MAYBE_CONST_EXPR, TREE_TYPE (ret), type_expr, ret); + C_MAYBE_CONST_EXPR_NON_CONST (ret) = !type_expr_const; + SET_EXPR_LOCATION (ret, loc); + } + + if (CAN_HAVE_LOCATION_P (ret) && !EXPR_HAS_LOCATION (ret)) + SET_EXPR_LOCATION (ret, loc); + + /* C++ does not permits types to be defined in a cast, but it + allows references to incomplete types. */ + if (warn_cxx_compat && type_name->specs->typespec_kind == ctsk_tagdef) + warning_at (loc, OPT_Wc___compat, + "defining a type in a cast is invalid in C++"); + + return ret; +} + +/* Build an assignment expression of lvalue LHS from value RHS. + If LHS_ORIGTYPE is not NULL, it is the original type of LHS, which + may differ from TREE_TYPE (LHS) for an enum bitfield. + 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. + If RHS_ORIGTYPE is not NULL_TREE, it is the original type of RHS, + which may differ from TREE_TYPE (RHS) for an enum value. + + LOCATION is the location of the MODIFYCODE operator. + RHS_LOC is the location of the RHS. */ + +tree +build_modify_expr (location_t location, tree lhs, tree lhs_origtype, + enum tree_code modifycode, + location_t rhs_loc, tree rhs, tree rhs_origtype) +{ + tree result; + tree newrhs; + tree rhs_semantic_type = NULL_TREE; + tree lhstype = TREE_TYPE (lhs); + tree olhstype = lhstype; + bool npc; + + /* 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; + + /* For ObjC properties, defer this check. */ + if (!objc_is_property_ref (lhs) && !lvalue_or_else (location, lhs, lv_assign)) + return error_mark_node; + + if (TREE_CODE (rhs) == EXCESS_PRECISION_EXPR) + { + rhs_semantic_type = TREE_TYPE (rhs); + rhs = TREE_OPERAND (rhs, 0); + } + + newrhs = rhs; + + if (TREE_CODE (lhs) == C_MAYBE_CONST_EXPR) + { + tree inner = build_modify_expr (location, C_MAYBE_CONST_EXPR_EXPR (lhs), + lhs_origtype, modifycode, rhs_loc, rhs, + rhs_origtype); + if (inner == error_mark_node) + return error_mark_node; + result = build2 (C_MAYBE_CONST_EXPR, TREE_TYPE (inner), + C_MAYBE_CONST_EXPR_PRE (lhs), inner); + gcc_assert (!C_MAYBE_CONST_EXPR_INT_OPERANDS (lhs)); + C_MAYBE_CONST_EXPR_NON_CONST (result) = 1; + protected_set_expr_location (result, location); + return result; + } + + /* 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 = c_fully_fold (lhs, false, NULL); + lhs = stabilize_reference (lhs); + newrhs = build_binary_op (location, + modifycode, lhs, rhs, 1); + + /* The original type of the right hand side is no longer + meaningful. */ + rhs_origtype = NULL_TREE; + } + + if (c_dialect_objc ()) + { + /* Check if we are modifying an Objective-C property reference; + if so, we need to generate setter calls. */ + result = objc_maybe_build_modify_expr (lhs, newrhs); + if (result) + return result; + + /* Else, do the check that we postponed for Objective-C. */ + if (!lvalue_or_else (location, lhs, lv_assign)) + return error_mark_node; + } + + /* Give an error for storing in something that is 'const'. */ + + if (TYPE_READONLY (lhstype) + || ((TREE_CODE (lhstype) == RECORD_TYPE + || TREE_CODE (lhstype) == UNION_TYPE) + && C_TYPE_FIELDS_READONLY (lhstype))) + { + readonly_error (lhs, lv_assign); + return error_mark_node; + } + else if (TREE_READONLY (lhs)) + readonly_warning (lhs, lv_assign); + + /* 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) == BOOLEAN_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; + } + + /* Issue -Wc++-compat warnings about an assignment to an enum type + when LHS does not have its original type. This happens for, + e.g., an enum bitfield in a struct. */ + if (warn_cxx_compat + && lhs_origtype != NULL_TREE + && lhs_origtype != lhstype + && TREE_CODE (lhs_origtype) == ENUMERAL_TYPE) + { + tree checktype = (rhs_origtype != NULL_TREE + ? rhs_origtype + : TREE_TYPE (rhs)); + if (checktype != error_mark_node + && TYPE_MAIN_VARIANT (checktype) != TYPE_MAIN_VARIANT (lhs_origtype)) + warning_at (location, OPT_Wc___compat, + "enum conversion in assignment is invalid in C++"); + } + + /* Convert new value to destination type. Fold it first, then + restore any excess precision information, for the sake of + conversion warnings. */ + + npc = null_pointer_constant_p (newrhs); + newrhs = c_fully_fold (newrhs, false, NULL); + if (rhs_semantic_type) + newrhs = build1 (EXCESS_PRECISION_EXPR, rhs_semantic_type, newrhs); + newrhs = convert_for_assignment (location, lhstype, newrhs, rhs_origtype, + ic_assign, npc, NULL_TREE, NULL_TREE, 0); + if (TREE_CODE (newrhs) == ERROR_MARK) + return error_mark_node; + + /* Emit ObjC write barrier, if necessary. */ + if (c_dialect_objc () && flag_objc_gc) + { + result = objc_generate_write_barrier (lhs, modifycode, newrhs); + if (result) + { + protected_set_expr_location (result, location); + return result; + } + } + + /* Scan operands. */ + + result = build2 (MODIFY_EXPR, lhstype, lhs, newrhs); + TREE_SIDE_EFFECTS (result) = 1; + protected_set_expr_location (result, location); + + /* 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; + + result = convert_for_assignment (location, olhstype, result, rhs_origtype, + ic_assign, false, NULL_TREE, NULL_TREE, 0); + protected_set_expr_location (result, location); + return result; +} + +/* Return whether STRUCT_TYPE has an anonymous field with type TYPE. + This is used to implement -fplan9-extensions. */ + +static bool +find_anonymous_field_with_type (tree struct_type, tree type) +{ + tree field; + bool found; + + gcc_assert (TREE_CODE (struct_type) == RECORD_TYPE + || TREE_CODE (struct_type) == UNION_TYPE); + found = false; + for (field = TYPE_FIELDS (struct_type); + field != NULL_TREE; + field = TREE_CHAIN (field)) + { + if (DECL_NAME (field) == NULL + && comptypes (type, TYPE_MAIN_VARIANT (TREE_TYPE (field)))) + { + if (found) + return false; + found = true; + } + else if (DECL_NAME (field) == NULL + && (TREE_CODE (TREE_TYPE (field)) == RECORD_TYPE + || TREE_CODE (TREE_TYPE (field)) == UNION_TYPE) + && find_anonymous_field_with_type (TREE_TYPE (field), type)) + { + if (found) + return false; + found = true; + } + } + return found; +} + +/* RHS is an expression whose type is pointer to struct. If there is + an anonymous field in RHS with type TYPE, then return a pointer to + that field in RHS. This is used with -fplan9-extensions. This + returns NULL if no conversion could be found. */ + +static tree +convert_to_anonymous_field (location_t location, tree type, tree rhs) +{ + tree rhs_struct_type, lhs_main_type; + tree field, found_field; + bool found_sub_field; + tree ret; + + gcc_assert (POINTER_TYPE_P (TREE_TYPE (rhs))); + rhs_struct_type = TREE_TYPE (TREE_TYPE (rhs)); + gcc_assert (TREE_CODE (rhs_struct_type) == RECORD_TYPE + || TREE_CODE (rhs_struct_type) == UNION_TYPE); + + gcc_assert (POINTER_TYPE_P (type)); + lhs_main_type = TYPE_MAIN_VARIANT (TREE_TYPE (type)); + + found_field = NULL_TREE; + found_sub_field = false; + for (field = TYPE_FIELDS (rhs_struct_type); + field != NULL_TREE; + field = TREE_CHAIN (field)) + { + if (DECL_NAME (field) != NULL_TREE + || (TREE_CODE (TREE_TYPE (field)) != RECORD_TYPE + && TREE_CODE (TREE_TYPE (field)) != UNION_TYPE)) + continue; + if (comptypes (lhs_main_type, TYPE_MAIN_VARIANT (TREE_TYPE (field)))) + { + if (found_field != NULL_TREE) + return NULL_TREE; + found_field = field; + } + else if (find_anonymous_field_with_type (TREE_TYPE (field), + lhs_main_type)) + { + if (found_field != NULL_TREE) + return NULL_TREE; + found_field = field; + found_sub_field = true; + } + } + + if (found_field == NULL_TREE) + return NULL_TREE; + + ret = fold_build3_loc (location, COMPONENT_REF, TREE_TYPE (found_field), + build_fold_indirect_ref (rhs), found_field, + NULL_TREE); + ret = build_fold_addr_expr_loc (location, ret); + + if (found_sub_field) + { + ret = convert_to_anonymous_field (location, type, ret); + gcc_assert (ret != NULL_TREE); + } + + return ret; +} + +/* Convert value RHS to type TYPE as preparation for an assignment to + an lvalue of type TYPE. If ORIGTYPE is not NULL_TREE, it is the + original type of RHS; this differs from TREE_TYPE (RHS) for enum + types. NULL_POINTER_CONSTANT says whether RHS was a null pointer + constant before any folding. + 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 says whether it is argument passing, assignment, + initialization or return. + + LOCATION is the location of the RHS. + FUNCTION is a tree for the function being called. + PARMNUM is the number of the argument, for printing in error messages. */ + +static tree +convert_for_assignment (location_t location, tree type, tree rhs, + tree origtype, enum impl_conv errtype, + bool null_pointer_constant, tree fundecl, + tree function, int parmnum) +{ + enum tree_code codel = TREE_CODE (type); + tree orig_rhs = rhs; + tree rhstype; + enum tree_code coder; + tree rname = NULL_TREE; + bool objc_ok = false; + + if (errtype == ic_argpass) + { + tree selector; + /* Change pointer to function to the function itself for + diagnostics. */ + if (TREE_CODE (function) == ADDR_EXPR + && TREE_CODE (TREE_OPERAND (function, 0)) == FUNCTION_DECL) + function = TREE_OPERAND (function, 0); + + /* Handle an ObjC selector specially for diagnostics. */ + selector = objc_message_selector (); + rname = function; + if (selector && parmnum > 2) + { + rname = selector; + parmnum -= 2; + } + } + + /* This macro is used to emit diagnostics to ensure that all format + strings are complete sentences, visible to gettext and checked at + compile time. */ +#define WARN_FOR_ASSIGNMENT(LOCATION, OPT, AR, AS, IN, RE) \ + do { \ + switch (errtype) \ + { \ + case ic_argpass: \ + if (pedwarn (LOCATION, OPT, AR, parmnum, rname)) \ + inform ((fundecl && !DECL_IS_BUILTIN (fundecl)) \ + ? DECL_SOURCE_LOCATION (fundecl) : LOCATION, \ + "expected %qT but argument is of type %qT", \ + type, rhstype); \ + break; \ + case ic_assign: \ + pedwarn (LOCATION, OPT, AS); \ + break; \ + case ic_init: \ + pedwarn_init (LOCATION, OPT, IN); \ + break; \ + case ic_return: \ + pedwarn (LOCATION, OPT, RE); \ + break; \ + default: \ + gcc_unreachable (); \ + } \ + } while (0) + + /* This macro is used to emit diagnostics to ensure that all format + strings are complete sentences, visible to gettext and checked at + compile time. It is the same as WARN_FOR_ASSIGNMENT but with an + extra parameter to enumerate qualifiers. */ + +#define WARN_FOR_QUALIFIERS(LOCATION, OPT, AR, AS, IN, RE, QUALS) \ + do { \ + switch (errtype) \ + { \ + case ic_argpass: \ + if (pedwarn (LOCATION, OPT, AR, parmnum, rname, QUALS)) \ + inform ((fundecl && !DECL_IS_BUILTIN (fundecl)) \ + ? DECL_SOURCE_LOCATION (fundecl) : LOCATION, \ + "expected %qT but argument is of type %qT", \ + type, rhstype); \ + break; \ + case ic_assign: \ + pedwarn (LOCATION, OPT, AS, QUALS); \ + break; \ + case ic_init: \ + pedwarn (LOCATION, OPT, IN, QUALS); \ + break; \ + case ic_return: \ + pedwarn (LOCATION, OPT, RE, QUALS); \ + break; \ + default: \ + gcc_unreachable (); \ + } \ + } while (0) + + if (TREE_CODE (rhs) == EXCESS_PRECISION_EXPR) + rhs = TREE_OPERAND (rhs, 0); + + rhstype = TREE_TYPE (rhs); + coder = TREE_CODE (rhstype); + + if (coder == ERROR_MARK) + return error_mark_node; + + if (c_dialect_objc ()) + { + int parmno; + + switch (errtype) + { + case ic_return: + parmno = 0; + break; + + case ic_assign: + parmno = -1; + break; + + case ic_init: + parmno = -2; + break; + + default: + parmno = parmnum; + break; + } + + objc_ok = objc_compare_types (type, rhstype, parmno, rname); + } + + if (warn_cxx_compat) + { + tree checktype = origtype != NULL_TREE ? origtype : rhstype; + if (checktype != error_mark_node + && TREE_CODE (type) == ENUMERAL_TYPE + && TYPE_MAIN_VARIANT (checktype) != TYPE_MAIN_VARIANT (type)) + { + WARN_FOR_ASSIGNMENT (input_location, OPT_Wc___compat, + G_("enum conversion when passing argument " + "%d of %qE is invalid in C++"), + G_("enum conversion in assignment is " + "invalid in C++"), + G_("enum conversion in initialization is " + "invalid in C++"), + G_("enum conversion in return is " + "invalid in C++")); + } + } + + if (TYPE_MAIN_VARIANT (type) == TYPE_MAIN_VARIANT (rhstype)) + return rhs; + + if (coder == VOID_TYPE) + { + /* Except for passing an argument to an unprototyped function, + this is a constraint violation. When passing an argument to + an unprototyped function, it is compile-time undefined; + making it a constraint in that case was rejected in + DR#252. */ + error_at (location, "void value not ignored as it ought to be"); + return error_mark_node; + } + rhs = require_complete_type (rhs); + if (rhs == error_mark_node) + return error_mark_node; + /* A type converts to a reference to it. + This code doesn't fully support references, it's just for the + special case of va_start and va_copy. */ + if (codel == REFERENCE_TYPE + && comptypes (TREE_TYPE (type), TREE_TYPE (rhs)) == 1) + { + if (!lvalue_p (rhs)) + { + error_at (location, "cannot pass rvalue to reference parameter"); + return error_mark_node; + } + if (!c_mark_addressable (rhs)) + return error_mark_node; + rhs = build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (rhs)), rhs); + SET_EXPR_LOCATION (rhs, location); + + /* We already know that these two types are compatible, but they + may not be exactly identical. In fact, `TREE_TYPE (type)' is + likely to be __builtin_va_list and `TREE_TYPE (rhs)' is + likely to be va_list, a typedef to __builtin_va_list, which + is different enough that it will cause problems later. */ + if (TREE_TYPE (TREE_TYPE (rhs)) != TREE_TYPE (type)) + { + rhs = build1 (NOP_EXPR, build_pointer_type (TREE_TYPE (type)), rhs); + SET_EXPR_LOCATION (rhs, location); + } + + rhs = build1 (NOP_EXPR, type, rhs); + SET_EXPR_LOCATION (rhs, location); + return rhs; + } + /* Some types can interconvert without explicit casts. */ + else if (codel == VECTOR_TYPE && coder == VECTOR_TYPE + && vector_types_convertible_p (type, TREE_TYPE (rhs), true)) + return convert (type, rhs); + /* Arithmetic types all interconvert, and enum is treated like int. */ + else if ((codel == INTEGER_TYPE || codel == REAL_TYPE + || codel == FIXED_POINT_TYPE + || codel == ENUMERAL_TYPE || codel == COMPLEX_TYPE + || codel == BOOLEAN_TYPE) + && (coder == INTEGER_TYPE || coder == REAL_TYPE + || coder == FIXED_POINT_TYPE + || coder == ENUMERAL_TYPE || coder == COMPLEX_TYPE + || coder == BOOLEAN_TYPE)) + { + tree ret; + bool save = in_late_binary_op; + if (codel == BOOLEAN_TYPE || codel == COMPLEX_TYPE) + in_late_binary_op = true; + ret = convert_and_check (type, orig_rhs); + if (codel == BOOLEAN_TYPE || codel == COMPLEX_TYPE) + in_late_binary_op = save; + return ret; + } + + /* Aggregates in different TUs might need conversion. */ + if ((codel == RECORD_TYPE || codel == UNION_TYPE) + && codel == coder + && comptypes (type, rhstype)) + return convert_and_check (type, rhs); + + /* Conversion to a transparent union or record from its member types. + This applies only to function arguments. */ + if (((codel == UNION_TYPE || codel == RECORD_TYPE) + && TYPE_TRANSPARENT_AGGR (type)) + && errtype == ic_argpass) + { + tree memb, marginal_memb = NULL_TREE; + + for (memb = TYPE_FIELDS (type); memb ; memb = DECL_CHAIN (memb)) + { + tree memb_type = TREE_TYPE (memb); + + if (comptypes (TYPE_MAIN_VARIANT (memb_type), + TYPE_MAIN_VARIANT (rhstype))) + break; + + if (TREE_CODE (memb_type) != POINTER_TYPE) + continue; + + if (coder == POINTER_TYPE) + { + tree ttl = TREE_TYPE (memb_type); + 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 (VOID_TYPE_P (ttl) || VOID_TYPE_P (ttr) + || comp_target_types (location, 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) + marginal_memb = memb; + } + } + + /* Can convert integer zero to any pointer type. */ + if (null_pointer_constant) + { + rhs = null_pointer_node; + break; + } + } + + if (memb || marginal_memb) + { + if (!memb) + { + /* We have only a marginally acceptable member type; + it needs a warning. */ + tree ttl = TREE_TYPE (TREE_TYPE (marginal_memb)); + 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_NO_ADDR_SPACE (ttl) + & ~TYPE_QUALS_NO_ADDR_SPACE (ttr)) + WARN_FOR_QUALIFIERS (location, 0, + G_("passing argument %d of %qE " + "makes %q#v qualified function " + "pointer from unqualified"), + G_("assignment makes %q#v qualified " + "function pointer from " + "unqualified"), + G_("initialization makes %q#v qualified " + "function pointer from " + "unqualified"), + G_("return makes %q#v qualified function " + "pointer from unqualified"), + TYPE_QUALS (ttl) & ~TYPE_QUALS (ttr)); + } + else if (TYPE_QUALS_NO_ADDR_SPACE (ttr) + & ~TYPE_QUALS_NO_ADDR_SPACE (ttl)) + WARN_FOR_QUALIFIERS (location, 0, + G_("passing argument %d of %qE discards " + "%qv qualifier from pointer target type"), + G_("assignment discards %qv qualifier " + "from pointer target type"), + G_("initialization discards %qv qualifier " + "from pointer target type"), + G_("return discards %qv qualifier from " + "pointer target type"), + TYPE_QUALS (ttr) & ~TYPE_QUALS (ttl)); + + memb = marginal_memb; + } + + if (!fundecl || !DECL_IN_SYSTEM_HEADER (fundecl)) + pedwarn (location, OPT_Wpedantic, + "ISO C prohibits argument conversion to union type"); + + rhs = fold_convert_loc (location, TREE_TYPE (memb), rhs); + return build_constructor_single (type, memb, rhs); + } + } + + /* Conversions among pointers */ + else if ((codel == POINTER_TYPE || codel == REFERENCE_TYPE) + && (coder == codel)) + { + tree ttl = TREE_TYPE (type); + tree ttr = TREE_TYPE (rhstype); + tree mvl = ttl; + tree mvr = ttr; + bool is_opaque_pointer; + int target_cmp = 0; /* Cache comp_target_types () result. */ + addr_space_t asl; + addr_space_t asr; + + if (TREE_CODE (mvl) != ARRAY_TYPE) + mvl = TYPE_MAIN_VARIANT (mvl); + if (TREE_CODE (mvr) != ARRAY_TYPE) + mvr = TYPE_MAIN_VARIANT (mvr); + /* Opaque pointers are treated like void pointers. */ + is_opaque_pointer = vector_targets_convertible_p (ttl, ttr); + + /* The Plan 9 compiler permits a pointer to a struct to be + automatically converted into a pointer to an anonymous field + within the struct. */ + if (flag_plan9_extensions + && (TREE_CODE (mvl) == RECORD_TYPE || TREE_CODE(mvl) == UNION_TYPE) + && (TREE_CODE (mvr) == RECORD_TYPE || TREE_CODE(mvr) == UNION_TYPE) + && mvl != mvr) + { + tree new_rhs = convert_to_anonymous_field (location, type, rhs); + if (new_rhs != NULL_TREE) + { + rhs = new_rhs; + rhstype = TREE_TYPE (rhs); + coder = TREE_CODE (rhstype); + ttr = TREE_TYPE (rhstype); + mvr = TYPE_MAIN_VARIANT (ttr); + } + } + + /* C++ does not allow the implicit conversion void* -> T*. However, + for the purpose of reducing the number of false positives, we + tolerate the special case of + + int *p = NULL; + + where NULL is typically defined in C to be '(void *) 0'. */ + if (VOID_TYPE_P (ttr) && rhs != null_pointer_node && !VOID_TYPE_P (ttl)) + warning_at (location, OPT_Wc___compat, + "request for implicit conversion " + "from %qT to %qT not permitted in C++", rhstype, type); + + /* See if the pointers point to incompatible address spaces. */ + asl = TYPE_ADDR_SPACE (ttl); + asr = TYPE_ADDR_SPACE (ttr); + if (!null_pointer_constant_p (rhs) + && asr != asl && !targetm.addr_space.subset_p (asr, asl)) + { + switch (errtype) + { + case ic_argpass: + error_at (location, "passing argument %d of %qE from pointer to " + "non-enclosed address space", parmnum, rname); + break; + case ic_assign: + error_at (location, "assignment from pointer to " + "non-enclosed address space"); + break; + case ic_init: + error_at (location, "initialization from pointer to " + "non-enclosed address space"); + break; + case ic_return: + error_at (location, "return from pointer to " + "non-enclosed address space"); + break; + default: + gcc_unreachable (); + } + return error_mark_node; + } + + /* Check if the right-hand side has a format attribute but the + left-hand side doesn't. */ + if (warn_suggest_attribute_format + && check_missing_format_attribute (type, rhstype)) + { + switch (errtype) + { + case ic_argpass: + warning_at (location, OPT_Wsuggest_attribute_format, + "argument %d of %qE might be " + "a candidate for a format attribute", + parmnum, rname); + break; + case ic_assign: + warning_at (location, OPT_Wsuggest_attribute_format, + "assignment left-hand side might be " + "a candidate for a format attribute"); + break; + case ic_init: + warning_at (location, OPT_Wsuggest_attribute_format, + "initialization left-hand side might be " + "a candidate for a format attribute"); + break; + case ic_return: + warning_at (location, OPT_Wsuggest_attribute_format, + "return type might be " + "a candidate for a format attribute"); + break; + default: + gcc_unreachable (); + } + } + + /* 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 (VOID_TYPE_P (ttl) || VOID_TYPE_P (ttr) + || (target_cmp = comp_target_types (location, type, rhstype)) + || is_opaque_pointer + || (c_common_unsigned_type (mvl) + == c_common_unsigned_type (mvr))) + { + if (pedantic + && ((VOID_TYPE_P (ttl) && TREE_CODE (ttr) == FUNCTION_TYPE) + || + (VOID_TYPE_P (ttr) + && !null_pointer_constant + && TREE_CODE (ttl) == FUNCTION_TYPE))) + WARN_FOR_ASSIGNMENT (location, OPT_Wpedantic, + G_("ISO C forbids passing argument %d of " + "%qE between function pointer " + "and %<void *%>"), + G_("ISO C forbids assignment between " + "function pointer and %<void *%>"), + G_("ISO C forbids initialization between " + "function pointer and %<void *%>"), + G_("ISO C forbids return between function " + "pointer and %<void *%>")); + /* 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_NO_ADDR_SPACE (ttr) + & ~TYPE_QUALS_NO_ADDR_SPACE (ttl)) + { + WARN_FOR_QUALIFIERS (location, 0, + G_("passing argument %d of %qE discards " + "%qv qualifier from pointer target type"), + G_("assignment discards %qv qualifier " + "from pointer target type"), + G_("initialization discards %qv qualifier " + "from pointer target type"), + G_("return discards %qv qualifier from " + "pointer target type"), + TYPE_QUALS (ttr) & ~TYPE_QUALS (ttl)); + } + /* If this is not a case of ignoring a mismatch in signedness, + no warning. */ + else if (VOID_TYPE_P (ttl) || VOID_TYPE_P (ttr) + || target_cmp) + ; + /* If there is a mismatch, do warn. */ + else if (warn_pointer_sign) + WARN_FOR_ASSIGNMENT (location, OPT_Wpointer_sign, + G_("pointer targets in passing argument " + "%d of %qE differ in signedness"), + G_("pointer targets in assignment " + "differ in signedness"), + G_("pointer targets in initialization " + "differ in signedness"), + G_("pointer targets in return differ " + "in signedness")); + } + 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_NO_ADDR_SPACE (ttl) + & ~TYPE_QUALS_NO_ADDR_SPACE (ttr)) + WARN_FOR_QUALIFIERS (location, 0, + G_("passing argument %d of %qE makes " + "%q#v qualified function pointer " + "from unqualified"), + G_("assignment makes %q#v qualified function " + "pointer from unqualified"), + G_("initialization makes %q#v qualified " + "function pointer from unqualified"), + G_("return makes %q#v qualified function " + "pointer from unqualified"), + TYPE_QUALS (ttl) & ~TYPE_QUALS (ttr)); + } + } + else + /* Avoid warning about the volatile ObjC EH puts on decls. */ + if (!objc_ok) + WARN_FOR_ASSIGNMENT (location, 0, + G_("passing argument %d of %qE from " + "incompatible pointer type"), + G_("assignment from incompatible pointer type"), + G_("initialization from incompatible " + "pointer type"), + G_("return from incompatible pointer type")); + + return convert (type, rhs); + } + else if (codel == POINTER_TYPE && coder == ARRAY_TYPE) + { + /* ??? This should not be an error when inlining calls to + unprototyped functions. */ + error_at (location, "invalid use of non-lvalue array"); + return error_mark_node; + } + 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 (!null_pointer_constant) + WARN_FOR_ASSIGNMENT (location, 0, + G_("passing argument %d of %qE makes " + "pointer from integer without a cast"), + G_("assignment makes pointer from integer " + "without a cast"), + G_("initialization makes pointer from " + "integer without a cast"), + G_("return makes pointer from integer " + "without a cast")); + + return convert (type, rhs); + } + else if (codel == INTEGER_TYPE && coder == POINTER_TYPE) + { + WARN_FOR_ASSIGNMENT (location, 0, + G_("passing argument %d of %qE makes integer " + "from pointer without a cast"), + G_("assignment makes integer from pointer " + "without a cast"), + G_("initialization makes integer from pointer " + "without a cast"), + G_("return makes integer from pointer " + "without a cast")); + return convert (type, rhs); + } + else if (codel == BOOLEAN_TYPE && coder == POINTER_TYPE) + { + tree ret; + bool save = in_late_binary_op; + in_late_binary_op = true; + ret = convert (type, rhs); + in_late_binary_op = save; + return ret; + } + + switch (errtype) + { + case ic_argpass: + error_at (location, "incompatible type for argument %d of %qE", parmnum, rname); + inform ((fundecl && !DECL_IS_BUILTIN (fundecl)) + ? DECL_SOURCE_LOCATION (fundecl) : input_location, + "expected %qT but argument is of type %qT", type, rhstype); + break; + case ic_assign: + error_at (location, "incompatible types when assigning to type %qT from " + "type %qT", type, rhstype); + break; + case ic_init: + error_at (location, + "incompatible types when initializing type %qT using type %qT", + type, rhstype); + break; + case ic_return: + error_at (location, + "incompatible types when returning type %qT but %qT was " + "expected", rhstype, type); + break; + default: + gcc_unreachable (); + } + + return error_mark_node; +} + +/* 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 (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 (!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 ORIGTYPE is not NULL_TREE, it is the original type of INIT. + If the init is invalid, store an ERROR_MARK. + + INIT_LOC is the location of the initial value. */ + +void +store_init_value (location_t init_loc, tree decl, tree init, tree origtype) +{ + tree value, type; + bool npc = false; + + /* 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. */ + + if (init) + npc = null_pointer_constant_p (init); + value = digest_init (init_loc, type, init, origtype, npc, + true, TREE_STATIC (decl)); + + /* Store the expression if valid; else report error. */ + + if (!in_system_header + && AGGREGATE_TYPE_P (TREE_TYPE (decl)) && !TREE_STATIC (decl)) + warning (OPT_Wtraditional, "traditional C rejects automatic " + "aggregate initialization"); + + DECL_INITIAL (decl) = value; + + /* ANSI wants warnings about out-of-range constant initializers. */ + STRIP_TYPE_NOPS (value); + if (TREE_STATIC (decl)) + constant_expression_warning (value); + + /* Check if we need to set array size from compound literal size. */ + if (TREE_CODE (type) == ARRAY_TYPE + && TYPE_DOMAIN (type) == 0 + && value != error_mark_node) + { + tree inside_init = init; + + STRIP_TYPE_NOPS (inside_init); + inside_init = fold (inside_init); + + if (TREE_CODE (inside_init) == COMPOUND_LITERAL_EXPR) + { + tree cldecl = COMPOUND_LITERAL_EXPR_DECL (inside_init); + + if (TYPE_DOMAIN (TREE_TYPE (cldecl))) + { + /* For int foo[] = (int [3]){1}; we need to set array size + now since later on array initializer will be just the + brace enclosed list of the compound literal. */ + tree etype = strip_array_types (TREE_TYPE (decl)); + type = build_distinct_type_copy (TYPE_MAIN_VARIANT (type)); + TYPE_DOMAIN (type) = TYPE_DOMAIN (TREE_TYPE (cldecl)); + layout_type (type); + layout_decl (cldecl, 0); + TREE_TYPE (decl) + = c_build_qualified_type (type, TYPE_QUALS (etype)); + } + } + } +} + +/* 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 + { + unsigned HOST_WIDE_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)) + +/* 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; \ + spelling_base = XRESIZEVEC (struct spelling, spelling_base, \ + spelling_size); \ + RESTORE_SPELLING_DEPTH (depth); \ + } \ + \ + spelling->kind = (KIND); \ + spelling->MEMBER = (VALUE); \ + spelling++; \ +} + +/* Push STRING on the stack. Printed literally. */ + +static void +push_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 (tree decl) +{ + const char *const string + = (DECL_NAME (decl) + ? identifier_to_locale (IDENTIFIER_POINTER (DECL_NAME (decl))) + : _("<anonymous>")); + PUSH_SPELLING (SPELLING_MEMBER, string, u.s); +} + +/* Push an array bounds on the stack. Printed as [BOUNDS]. */ + +static void +push_array_bounds (unsigned HOST_WIDE_INT bounds) +{ + PUSH_SPELLING (SPELLING_BOUNDS, bounds, u.i); +} + +/* Compute the maximum size in bytes of the printed spelling. */ + +static int +spelling_length (void) +{ + int size = 0; + 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 (char *buffer) +{ + char *d = buffer; + struct spelling *p; + + for (p = spelling_base; p < spelling; p++) + if (p->kind == SPELLING_BOUNDS) + { + sprintf (d, "[" HOST_WIDE_INT_PRINT_UNSIGNED "]", p->u.i); + d += strlen (d); + } + else + { + 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. + GMSGID identifies the message. + The component name is taken from the spelling stack. */ + +void +error_init (const char *gmsgid) +{ + char *ofwhat; + + /* The gmsgid may be a format string with %< and %>. */ + error (gmsgid); + ofwhat = print_spelling ((char *) alloca (spelling_length () + 1)); + if (*ofwhat) + error ("(near initialization for %qs)", ofwhat); +} + +/* Issue a pedantic warning for a bad initializer component. OPT is + the option OPT_* (from options.h) controlling this warning or 0 if + it is unconditionally given. GMSGID identifies the message. The + component name is taken from the spelling stack. */ + +void +pedwarn_init (location_t location, int opt, const char *gmsgid) +{ + char *ofwhat; + + /* The gmsgid may be a format string with %< and %>. */ + pedwarn (location, opt, gmsgid); + ofwhat = print_spelling ((char *) alloca (spelling_length () + 1)); + if (*ofwhat) + pedwarn (location, opt, "(near initialization for %qs)", ofwhat); +} + +/* Issue a warning for a bad initializer component. + + OPT is the OPT_W* value corresponding to the warning option that + controls this warning. GMSGID identifies the message. The + component name is taken from the spelling stack. */ + +static void +warning_init (int opt, const char *gmsgid) +{ + char *ofwhat; + + /* The gmsgid may be a format string with %< and %>. */ + warning (opt, gmsgid); + ofwhat = print_spelling ((char *) alloca (spelling_length () + 1)); + if (*ofwhat) + warning (opt, "(near initialization for %qs)", ofwhat); +} + +/* If TYPE is an array type and EXPR is a parenthesized string + constant, warn if pedantic that EXPR is being used to initialize an + object of type TYPE. */ + +void +maybe_warn_string_init (tree type, struct c_expr expr) +{ + if (pedantic + && TREE_CODE (type) == ARRAY_TYPE + && TREE_CODE (expr.value) == STRING_CST + && expr.original_code != STRING_CST) + pedwarn_init (input_location, OPT_Wpedantic, + "array initialized from parenthesized string constant"); +} + +/* Digest the parser output INIT as an initializer for type TYPE. + Return a C expression of type TYPE to represent the initial value. + + If ORIGTYPE is not NULL_TREE, it is the original type of INIT. + + NULL_POINTER_CONSTANT is true if INIT is a null pointer constant. + + If INIT is a string constant, STRICT_STRING is true if it is + unparenthesized or we should not warn here for it being parenthesized. + For other types of INIT, STRICT_STRING is not used. + + INIT_LOC is the location of the INIT. + + REQUIRE_CONSTANT requests an error if non-constant initializers or + elements are seen. */ + +static tree +digest_init (location_t init_loc, tree type, tree init, tree origtype, + bool null_pointer_constant, bool strict_string, + int require_constant) +{ + enum tree_code code = TREE_CODE (type); + tree inside_init = init; + tree semantic_type = NULL_TREE; + bool maybe_const = true; + + if (type == error_mark_node + || !init + || init == error_mark_node + || TREE_TYPE (init) == error_mark_node) + return error_mark_node; + + STRIP_TYPE_NOPS (inside_init); + + if (TREE_CODE (inside_init) == EXCESS_PRECISION_EXPR) + { + semantic_type = TREE_TYPE (inside_init); + inside_init = TREE_OPERAND (inside_init, 0); + } + inside_init = c_fully_fold (inside_init, require_constant, &maybe_const); + inside_init = decl_constant_value_for_optimization (inside_init); + + /* Initialization of an array of chars from a string constant + optionally enclosed in braces. */ + + if (code == ARRAY_TYPE && inside_init + && TREE_CODE (inside_init) == STRING_CST) + { + tree typ1 = TYPE_MAIN_VARIANT (TREE_TYPE (type)); + /* Note that an array could be both an array of character type + and an array of wchar_t if wchar_t is signed char or unsigned + char. */ + bool char_array = (typ1 == char_type_node + || typ1 == signed_char_type_node + || typ1 == unsigned_char_type_node); + bool wchar_array = !!comptypes (typ1, wchar_type_node); + bool char16_array = !!comptypes (typ1, char16_type_node); + bool char32_array = !!comptypes (typ1, char32_type_node); + + if (char_array || wchar_array || char16_array || char32_array) + { + struct c_expr expr; + tree typ2 = TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (inside_init))); + expr.value = inside_init; + expr.original_code = (strict_string ? STRING_CST : ERROR_MARK); + expr.original_type = NULL; + maybe_warn_string_init (type, expr); + + if (TYPE_DOMAIN (type) && !TYPE_MAX_VALUE (TYPE_DOMAIN (type))) + pedwarn_init (init_loc, OPT_Wpedantic, + "initialization of a flexible array member"); + + if (comptypes (TYPE_MAIN_VARIANT (TREE_TYPE (inside_init)), + TYPE_MAIN_VARIANT (type))) + return inside_init; + + if (char_array) + { + if (typ2 != char_type_node) + { + error_init ("char-array initialized from wide string"); + return error_mark_node; + } + } + else + { + if (typ2 == char_type_node) + { + error_init ("wide character array initialized from non-wide " + "string"); + return error_mark_node; + } + else if (!comptypes(typ1, typ2)) + { + error_init ("wide character array initialized from " + "incompatible wide string"); + return error_mark_node; + } + } + + TREE_TYPE (inside_init) = type; + if (TYPE_DOMAIN (type) != 0 + && TYPE_SIZE (type) != 0 + && TREE_CODE (TYPE_SIZE (type)) == INTEGER_CST) + { + unsigned HOST_WIDE_INT len = TREE_STRING_LENGTH (inside_init); + + /* Subtract the size of a single (possibly wide) character + because it's ok to ignore the terminating null char + that is counted in the length of the constant. */ + if (0 > compare_tree_int (TYPE_SIZE_UNIT (type), + (len + - (TYPE_PRECISION (typ1) + / BITS_PER_UNIT)))) + pedwarn_init (init_loc, 0, + ("initializer-string for array of chars " + "is too long")); + else if (warn_cxx_compat + && 0 > compare_tree_int (TYPE_SIZE_UNIT (type), len)) + warning_at (init_loc, OPT_Wc___compat, + ("initializer-string for array chars " + "is too long for C++")); + } + + return inside_init; + } + else if (INTEGRAL_TYPE_P (typ1)) + { + error_init ("array of inappropriate type initialized " + "from string constant"); + return error_mark_node; + } + } + + /* Build a VECTOR_CST from a *constant* vector constructor. If the + vector constructor is not constant (e.g. {1,2,3,foo()}) then punt + below and handle as a constructor. */ + if (code == VECTOR_TYPE + && TREE_CODE (TREE_TYPE (inside_init)) == VECTOR_TYPE + && vector_types_convertible_p (TREE_TYPE (inside_init), type, true) + && TREE_CONSTANT (inside_init)) + { + if (TREE_CODE (inside_init) == VECTOR_CST + && comptypes (TYPE_MAIN_VARIANT (TREE_TYPE (inside_init)), + TYPE_MAIN_VARIANT (type))) + return inside_init; + + if (TREE_CODE (inside_init) == CONSTRUCTOR) + { + unsigned HOST_WIDE_INT ix; + tree value; + bool constant_p = true; + + /* Iterate through elements and check if all constructor + elements are *_CSTs. */ + FOR_EACH_CONSTRUCTOR_VALUE (CONSTRUCTOR_ELTS (inside_init), ix, value) + if (!CONSTANT_CLASS_P (value)) + { + constant_p = false; + break; + } + + if (constant_p) + return build_vector_from_ctor (type, + CONSTRUCTOR_ELTS (inside_init)); + } + } + + if (warn_sequence_point) + verify_sequence_points (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 == VECTOR_TYPE + && comptypes (TREE_TYPE (inside_init), type)) + || (code == POINTER_TYPE + && TREE_CODE (TREE_TYPE (inside_init)) == ARRAY_TYPE + && comptypes (TREE_TYPE (TREE_TYPE (inside_init)), + TREE_TYPE (type))))) + { + if (code == POINTER_TYPE) + { + if (TREE_CODE (TREE_TYPE (inside_init)) == ARRAY_TYPE) + { + if (TREE_CODE (inside_init) == STRING_CST + || TREE_CODE (inside_init) == COMPOUND_LITERAL_EXPR) + inside_init = array_to_pointer_conversion + (init_loc, inside_init); + else + { + error_init ("invalid use of non-lvalue array"); + return error_mark_node; + } + } + } + + if (code == VECTOR_TYPE) + /* Although the types are compatible, we may require a + conversion. */ + inside_init = convert (type, inside_init); + + if (require_constant + && (code == VECTOR_TYPE || !flag_isoc99) + && TREE_CODE (inside_init) == COMPOUND_LITERAL_EXPR) + { + /* As an extension, allow initializing objects with static storage + duration with compound literals (which are then treated just as + the brace enclosed list they contain). Also allow this for + vectors, as we can only assign them with compound literals. */ + tree decl = COMPOUND_LITERAL_EXPR_DECL (inside_init); + inside_init = DECL_INITIAL (decl); + } + + 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; + } + + /* Compound expressions can only occur here if -Wpedantic 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 (init_loc, OPT_Wpedantic, + "initializer element is not constant"); + if (flag_pedantic_errors) + inside_init = error_mark_node; + } + else if (require_constant + && !initializer_constant_valid_p (inside_init, + TREE_TYPE (inside_init))) + { + error_init ("initializer element is not constant"); + inside_init = error_mark_node; + } + else if (require_constant && !maybe_const) + pedwarn_init (init_loc, 0, + "initializer element is not a constant expression"); + + /* Added to enable additional -Wsuggest-attribute=format warnings. */ + if (TREE_CODE (TREE_TYPE (inside_init)) == POINTER_TYPE) + inside_init = convert_for_assignment (init_loc, type, inside_init, + origtype, + ic_init, null_pointer_constant, + NULL_TREE, NULL_TREE, 0); + return inside_init; + } + + /* Handle scalar types, including conversions. */ + + if (code == INTEGER_TYPE || code == REAL_TYPE || code == FIXED_POINT_TYPE + || code == POINTER_TYPE || code == ENUMERAL_TYPE || code == BOOLEAN_TYPE + || code == COMPLEX_TYPE || code == VECTOR_TYPE) + { + if (TREE_CODE (TREE_TYPE (init)) == ARRAY_TYPE + && (TREE_CODE (init) == STRING_CST + || TREE_CODE (init) == COMPOUND_LITERAL_EXPR)) + inside_init = init = array_to_pointer_conversion (init_loc, init); + if (semantic_type) + inside_init = build1 (EXCESS_PRECISION_EXPR, semantic_type, + inside_init); + inside_init + = convert_for_assignment (init_loc, type, inside_init, origtype, + ic_init, null_pointer_constant, + NULL_TREE, NULL_TREE, 0); + + /* Check to see if we have already given an error message. */ + if (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))) + { + error_init ("initializer element is not computable at load time"); + inside_init = error_mark_node; + } + else if (require_constant && !maybe_const) + pedwarn_init (init_loc, 0, + "initializer element is not a constant expression"); + + return inside_init; + } + + /* Come here only for records and arrays. */ + + if (COMPLETE_TYPE_P (type) && TREE_CODE (TYPE_SIZE (type)) != INTEGER_CST) + { + error_init ("variable-sized object may not be initialized"); + 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. */ +static tree constructor_index; + +/* 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. */ +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. */ +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 VEC(constructor_elt,gc) *constructor_elements; + +/* 1 if constructor should be incrementally stored into a constructor chain, + 0 if all the elements should be kept in AVL tree. */ +static int constructor_incremental; + +/* 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 has an element that cannot be part of a + constant expression. */ +static int constructor_nonconst; + +/* 1 if this constructor is erroneous so far. */ +static int constructor_erroneous; + +/* 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 origtype; +}; + +/* 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. + Will never hold tree nodes across GC runs. */ +static struct init_node *constructor_pending_elts; + +/* The SPELLING_DEPTH of this constructor. */ +static int constructor_depth; + +/* 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; + +/* Nonzero if this is an initializer for a top-level decl. */ +static int constructor_top_level; + +/* Nonzero if there were any member designators in this initializer. */ +static int constructor_designated; + +/* Nesting depth of designator list. */ +static int designator_depth; + +/* Nonzero if there were diagnosed errors in this designator list. */ +static int designator_erroneous; + + +/* 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_range_stack; + +struct constructor_stack +{ + struct constructor_stack *next; + tree type; + tree fields; + tree index; + tree max_index; + tree unfilled_index; + tree unfilled_fields; + tree bit_index; + VEC(constructor_elt,gc) *elements; + struct init_node *pending_elts; + int offset; + int depth; + /* If value nonzero, this value should replace the entire + constructor at this level. */ + struct c_expr replacement_value; + struct constructor_range_stack *range_stack; + char constant; + char simple; + char nonconst; + char implicit; + char erroneous; + char outer; + char incremental; + char designated; +}; + +static struct constructor_stack *constructor_stack; + +/* This stack represents designators from some range designator up to + the last designator in the list. */ + +struct constructor_range_stack +{ + struct constructor_range_stack *next, *prev; + struct constructor_stack *stack; + tree range_start; + tree index; + tree range_end; + tree fields; +}; + +static struct constructor_range_stack *constructor_range_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; + struct constructor_stack *constructor_stack; + struct constructor_range_stack *constructor_range_stack; + VEC(constructor_elt,gc) *elements; + struct spelling *spelling; + struct spelling *spelling_base; + int spelling_size; + char top_level; + char require_constant_value; + char require_constant_elements; +}; + +static struct initializer_stack *initializer_stack; + +/* Prepare to parse and output the initializer for variable DECL. */ + +void +start_init (tree decl, tree asmspec_tree ATTRIBUTE_UNUSED, int top_level) +{ + const char *locus; + struct initializer_stack *p = XNEW (struct initializer_stack); + + p->decl = constructor_decl; + p->require_constant_value = require_constant_value; + p->require_constant_elements = require_constant_elements; + p->constructor_stack = constructor_stack; + p->constructor_range_stack = constructor_range_stack; + p->elements = constructor_elements; + p->spelling = spelling; + p->spelling_base = spelling_base; + p->spelling_size = spelling_size; + p->top_level = constructor_top_level; + p->next = initializer_stack; + initializer_stack = p; + + constructor_decl = decl; + constructor_designated = 0; + constructor_top_level = top_level; + + if (decl != 0 && decl != error_mark_node) + { + require_constant_value = TREE_STATIC (decl); + require_constant_elements + = ((TREE_STATIC (decl) || (pedantic && !flag_isoc99)) + /* 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_to_locale (IDENTIFIER_POINTER (DECL_NAME (decl))); + } + else + { + require_constant_value = 0; + require_constant_elements = 0; + locus = _("(anonymous)"); + } + + constructor_stack = 0; + constructor_range_stack = 0; + + missing_braces_mentioned = 0; + + spelling_base = 0; + spelling_size = 0; + RESTORE_SPELLING_DEPTH (0); + + if (locus) + push_string (locus); +} + +void +finish_init (void) +{ + struct initializer_stack *p = initializer_stack; + + /* Free the whole constructor stack of this initializer. */ + while (constructor_stack) + { + struct constructor_stack *q = constructor_stack; + constructor_stack = q->next; + free (q); + } + + gcc_assert (!constructor_range_stack); + + /* Pop back to the data of the outer initializer (if any). */ + free (spelling_base); + + constructor_decl = p->decl; + require_constant_value = p->require_constant_value; + require_constant_elements = p->require_constant_elements; + constructor_stack = p->constructor_stack; + constructor_range_stack = p->constructor_range_stack; + constructor_elements = p->elements; + spelling = p->spelling; + spelling_base = p->spelling_base; + spelling_size = p->spelling_size; + 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 (tree type) +{ + struct constructor_stack *p = XNEW (struct constructor_stack); + + if (type == 0) + type = TREE_TYPE (constructor_decl); + + if (TREE_CODE (type) == VECTOR_TYPE + && TYPE_VECTOR_OPAQUE (type)) + error ("opaque vector types cannot be initialized"); + + p->type = constructor_type; + p->fields = constructor_fields; + p->index = constructor_index; + 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->nonconst = constructor_nonconst; + p->erroneous = constructor_erroneous; + p->pending_elts = constructor_pending_elts; + p->depth = constructor_depth; + p->replacement_value.value = 0; + p->replacement_value.original_code = ERROR_MARK; + p->replacement_value.original_type = NULL; + p->implicit = 0; + p->range_stack = 0; + p->outer = 0; + p->incremental = constructor_incremental; + p->designated = constructor_designated; + p->next = 0; + constructor_stack = p; + + constructor_constant = 1; + constructor_simple = 1; + constructor_nonconst = 0; + constructor_depth = SPELLING_DEPTH (); + constructor_elements = 0; + constructor_pending_elts = 0; + constructor_type = type; + constructor_incremental = 1; + constructor_designated = 0; + designator_depth = 0; + designator_erroneous = 0; + + 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 = DECL_CHAIN (constructor_fields); + + constructor_unfilled_fields = constructor_fields; + constructor_bit_index = bitsize_zero_node; + } + else if (TREE_CODE (constructor_type) == ARRAY_TYPE) + { + if (TYPE_DOMAIN (constructor_type)) + { + constructor_max_index + = TYPE_MAX_VALUE (TYPE_DOMAIN (constructor_type)); + + /* Detect non-empty initializations of zero-length arrays. */ + if (constructor_max_index == NULL_TREE + && TYPE_SIZE (constructor_type)) + constructor_max_index = integer_minus_one_node; + + /* constructor_max_index needs to be an INTEGER_CST. Attempts + to initialize VLAs will cause a proper error; avoid tree + checking errors as well by setting a safe value. */ + if (constructor_max_index + && TREE_CODE (constructor_max_index) != INTEGER_CST) + constructor_max_index = integer_minus_one_node; + + constructor_index + = convert (bitsizetype, + TYPE_MIN_VALUE (TYPE_DOMAIN (constructor_type))); + } + else + { + constructor_index = bitsize_zero_node; + constructor_max_index = NULL_TREE; + } + + constructor_unfilled_index = constructor_index; + } + else if (TREE_CODE (constructor_type) == VECTOR_TYPE) + { + /* Vectors are like simple fixed-size arrays. */ + constructor_max_index = + bitsize_int (TYPE_VECTOR_SUBPARTS (constructor_type) - 1); + constructor_index = bitsize_zero_node; + constructor_unfilled_index = constructor_index; + } + else + { + /* Handle the case of int x = {5}; */ + constructor_fields = constructor_type; + constructor_unfilled_fields = constructor_type; + } +} + +/* 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 (or 2 if the push is because of designator list). */ + +void +push_init_level (int implicit, struct obstack * braced_init_obstack) +{ + struct constructor_stack *p; + tree value = NULL_TREE; + + /* If we've exhausted any levels that didn't have braces, + pop them now. If implicit == 1, this will have been done in + process_init_element; do not repeat it here because in the case + of excess initializers for an empty aggregate this leads to an + infinite cycle of popping a level and immediately recreating + it. */ + if (implicit != 1) + { + 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, braced_init_obstack), + true, braced_init_obstack); + else if (TREE_CODE (constructor_type) == ARRAY_TYPE + && constructor_max_index + && tree_int_cst_lt (constructor_max_index, + constructor_index)) + process_init_element (pop_init_level (1, braced_init_obstack), + true, braced_init_obstack); + else + break; + } + } + + /* Unless this is an explicit brace, we need to preserve previous + content if any. */ + if (implicit) + { + if ((TREE_CODE (constructor_type) == RECORD_TYPE + || TREE_CODE (constructor_type) == UNION_TYPE) + && constructor_fields) + value = find_init_member (constructor_fields, braced_init_obstack); + else if (TREE_CODE (constructor_type) == ARRAY_TYPE) + value = find_init_member (constructor_index, braced_init_obstack); + } + + p = XNEW (struct constructor_stack); + p->type = constructor_type; + p->fields = constructor_fields; + p->index = constructor_index; + 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->nonconst = constructor_nonconst; + p->erroneous = constructor_erroneous; + p->pending_elts = constructor_pending_elts; + p->depth = constructor_depth; + p->replacement_value.value = 0; + p->replacement_value.original_code = ERROR_MARK; + p->replacement_value.original_type = NULL; + p->implicit = implicit; + p->outer = 0; + p->incremental = constructor_incremental; + p->designated = constructor_designated; + p->next = constructor_stack; + p->range_stack = 0; + constructor_stack = p; + + constructor_constant = 1; + constructor_simple = 1; + constructor_nonconst = 0; + constructor_depth = SPELLING_DEPTH (); + constructor_elements = 0; + constructor_incremental = 1; + constructor_designated = 0; + constructor_pending_elts = 0; + if (!implicit) + { + p->range_stack = constructor_range_stack; + constructor_range_stack = 0; + designator_depth = 0; + designator_erroneous = 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++; + } + } + else if (TREE_CODE (constructor_type) == ARRAY_TYPE) + { + constructor_type = TREE_TYPE (constructor_type); + push_array_bounds (tree_low_cst (constructor_index, 1)); + constructor_depth++; + } + + if (constructor_type == 0) + { + error_init ("extra brace group at end of initializer"); + constructor_fields = 0; + constructor_unfilled_fields = 0; + return; + } + + if (value && TREE_CODE (value) == CONSTRUCTOR) + { + constructor_constant = TREE_CONSTANT (value); + constructor_simple = TREE_STATIC (value); + constructor_nonconst = CONSTRUCTOR_NON_CONST (value); + constructor_elements = CONSTRUCTOR_ELTS (value); + if (!VEC_empty (constructor_elt, constructor_elements) + && (TREE_CODE (constructor_type) == RECORD_TYPE + || TREE_CODE (constructor_type) == ARRAY_TYPE)) + set_nonincremental_init (braced_init_obstack); + } + + if (implicit == 1 && warn_missing_braces && !missing_braces_mentioned) + { + missing_braces_mentioned = 1; + warning_init (OPT_Wmissing_braces, "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 = DECL_CHAIN (constructor_fields); + + constructor_unfilled_fields = constructor_fields; + constructor_bit_index = bitsize_zero_node; + } + else if (TREE_CODE (constructor_type) == VECTOR_TYPE) + { + /* Vectors are like simple fixed-size arrays. */ + constructor_max_index = + bitsize_int (TYPE_VECTOR_SUBPARTS (constructor_type) - 1); + constructor_index = bitsize_int (0); + constructor_unfilled_index = constructor_index; + } + else if (TREE_CODE (constructor_type) == ARRAY_TYPE) + { + if (TYPE_DOMAIN (constructor_type)) + { + constructor_max_index + = TYPE_MAX_VALUE (TYPE_DOMAIN (constructor_type)); + + /* Detect non-empty initializations of zero-length arrays. */ + if (constructor_max_index == NULL_TREE + && TYPE_SIZE (constructor_type)) + constructor_max_index = integer_minus_one_node; + + /* constructor_max_index needs to be an INTEGER_CST. Attempts + to initialize VLAs will cause a proper error; avoid tree + checking errors as well by setting a safe value. */ + if (constructor_max_index + && TREE_CODE (constructor_max_index) != INTEGER_CST) + constructor_max_index = integer_minus_one_node; + + constructor_index + = convert (bitsizetype, + TYPE_MIN_VALUE (TYPE_DOMAIN (constructor_type))); + } + else + constructor_index = bitsize_zero_node; + + constructor_unfilled_index = constructor_index; + if (value && TREE_CODE (value) == STRING_CST) + { + /* We need to split the char/wchar array into individual + characters, so that we don't have to special case it + everywhere. */ + set_nonincremental_init_from_string (value, braced_init_obstack); + } + } + else + { + if (constructor_type != error_mark_node) + warning_init (0, "braces around scalar initializer"); + constructor_fields = constructor_type; + constructor_unfilled_fields = constructor_type; + } +} + +/* At the end of an implicit or explicit brace level, + finish up that level of constructor. If a single expression + with redundant braces initialized that level, return the + c_expr structure for that expression. Otherwise, the original_code + element is set to ERROR_MARK. + If we were outputting the elements as they are read, return 0 as the value + from inner levels (process_init_element ignores that), + but return error_mark_node as the value from the outermost level + (that's what we want to put in DECL_INITIAL). + Otherwise, return a CONSTRUCTOR expression as the value. */ + +struct c_expr +pop_init_level (int implicit, struct obstack * braced_init_obstack) +{ + struct constructor_stack *p; + struct c_expr ret; + ret.value = 0; + ret.original_code = ERROR_MARK; + ret.original_type = NULL; + + 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, braced_init_obstack), + true, braced_init_obstack); + } + gcc_assert (!constructor_range_stack); + } + + /* Now output all pending elements. */ + constructor_incremental = 1; + output_pending_init_elements (1, braced_init_obstack); + + p = constructor_stack; + + /* Error for initializing a flexible array member, or a zero-length + array member in an inappropriate context. */ + if (constructor_type && constructor_fields + && TREE_CODE (constructor_type) == ARRAY_TYPE + && TYPE_DOMAIN (constructor_type) + && !TYPE_MAX_VALUE (TYPE_DOMAIN (constructor_type))) + { + /* Silently discard empty initializations. The parser will + already have pedwarned for empty brackets. */ + if (integer_zerop (constructor_unfilled_index)) + constructor_type = NULL_TREE; + else + { + gcc_assert (!TYPE_SIZE (constructor_type)); + + if (constructor_depth > 2) + error_init ("initialization of flexible array member in a nested context"); + else + pedwarn_init (input_location, OPT_Wpedantic, + "initialization of a flexible array member"); + + /* We have already issued an error message for the existence + of a flexible array member not at the end of the structure. + Discard the initializer so that we do not die later. */ + if (DECL_CHAIN (constructor_fields) != NULL_TREE) + constructor_type = NULL_TREE; + } + } + + /* Warn when some struct elements are implicitly initialized to zero. */ + if (warn_missing_field_initializers + && constructor_type + && TREE_CODE (constructor_type) == RECORD_TYPE + && constructor_unfilled_fields) + { + bool constructor_zeroinit = + (VEC_length (constructor_elt, constructor_elements) == 1 + && integer_zerop + (VEC_index (constructor_elt, constructor_elements, 0)->value)); + + /* Do not warn for flexible array members or zero-length arrays. */ + while (constructor_unfilled_fields + && (!DECL_SIZE (constructor_unfilled_fields) + || integer_zerop (DECL_SIZE (constructor_unfilled_fields)))) + constructor_unfilled_fields = DECL_CHAIN (constructor_unfilled_fields); + + if (constructor_unfilled_fields + /* Do not warn if this level of the initializer uses member + designators; it is likely to be deliberate. */ + && !constructor_designated + /* Do not warn about initializing with ` = {0}'. */ + && !constructor_zeroinit) + { + if (warning_at (input_location, OPT_Wmissing_field_initializers, + "missing initializer for field %qD of %qT", + constructor_unfilled_fields, + constructor_type)) + inform (DECL_SOURCE_LOCATION (constructor_unfilled_fields), + "%qD declared here", constructor_unfilled_fields); + } + } + + /* Pad out the end of the structure. */ + if (p->replacement_value.value) + /* If this closes a superfluous brace pair, + just pass out the element between them. */ + ret = p->replacement_value; + 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 + && TREE_CODE (constructor_type) != VECTOR_TYPE) + { + /* A nonincremental scalar initializer--just return + the element, after verifying there is just one. */ + if (VEC_empty (constructor_elt,constructor_elements)) + { + if (!constructor_erroneous) + error_init ("empty scalar initializer"); + ret.value = error_mark_node; + } + else if (VEC_length (constructor_elt,constructor_elements) != 1) + { + error_init ("extra elements in scalar initializer"); + ret.value = VEC_index (constructor_elt,constructor_elements,0)->value; + } + else + ret.value = VEC_index (constructor_elt,constructor_elements,0)->value; + } + else + { + if (constructor_erroneous) + ret.value = error_mark_node; + else + { + ret.value = build_constructor (constructor_type, + constructor_elements); + if (constructor_constant) + TREE_CONSTANT (ret.value) = 1; + if (constructor_constant && constructor_simple) + TREE_STATIC (ret.value) = 1; + if (constructor_nonconst) + CONSTRUCTOR_NON_CONST (ret.value) = 1; + } + } + + if (ret.value && TREE_CODE (ret.value) != CONSTRUCTOR) + { + if (constructor_nonconst) + ret.original_code = C_MAYBE_CONST_EXPR; + else if (ret.original_code == C_MAYBE_CONST_EXPR) + ret.original_code = ERROR_MARK; + } + + constructor_type = p->type; + constructor_fields = p->fields; + constructor_index = p->index; + 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_nonconst = p->nonconst; + constructor_erroneous = p->erroneous; + constructor_incremental = p->incremental; + constructor_designated = p->designated; + constructor_pending_elts = p->pending_elts; + constructor_depth = p->depth; + if (!p->implicit) + constructor_range_stack = p->range_stack; + RESTORE_SPELLING_DEPTH (constructor_depth); + + constructor_stack = p->next; + free (p); + + if (ret.value == 0 && constructor_stack == 0) + ret.value = error_mark_node; + return ret; +} + +/* Common handling for both array range and field name designators. + ARRAY argument is nonzero for array ranges. Returns zero for success. */ + +static int +set_designator (int array, struct obstack * braced_init_obstack) +{ + tree subtype; + enum tree_code subcode; + + /* Don't die if an entire brace-pair level is superfluous + in the containing level. */ + if (constructor_type == 0) + return 1; + + /* If there were errors in this designator list already, bail out + silently. */ + if (designator_erroneous) + return 1; + + if (!designator_depth) + { + gcc_assert (!constructor_range_stack); + + /* Designator list starts at the level of closest explicit + braces. */ + while (constructor_stack->implicit) + { + process_init_element (pop_init_level (1, braced_init_obstack), + true, braced_init_obstack); + } + constructor_designated = 1; + return 0; + } + + switch (TREE_CODE (constructor_type)) + { + case RECORD_TYPE: + case UNION_TYPE: + subtype = TREE_TYPE (constructor_fields); + if (subtype != error_mark_node) + subtype = TYPE_MAIN_VARIANT (subtype); + break; + case ARRAY_TYPE: + subtype = TYPE_MAIN_VARIANT (TREE_TYPE (constructor_type)); + break; + default: + gcc_unreachable (); + } + + subcode = TREE_CODE (subtype); + if (array && subcode != ARRAY_TYPE) + { + error_init ("array index in non-array initializer"); + return 1; + } + else if (!array && subcode != RECORD_TYPE && subcode != UNION_TYPE) + { + error_init ("field name not in record or union initializer"); + return 1; + } + + constructor_designated = 1; + push_init_level (2, braced_init_obstack); + return 0; +} + +/* If there are range designators in designator list, push a new designator + to constructor_range_stack. RANGE_END is end of such stack range or + NULL_TREE if there is no range designator at this level. */ + +static void +push_range_stack (tree range_end, struct obstack * braced_init_obstack) +{ + struct constructor_range_stack *p; + + p = (struct constructor_range_stack *) + obstack_alloc (braced_init_obstack, + sizeof (struct constructor_range_stack)); + p->prev = constructor_range_stack; + p->next = 0; + p->fields = constructor_fields; + p->range_start = constructor_index; + p->index = constructor_index; + p->stack = constructor_stack; + p->range_end = range_end; + if (constructor_range_stack) + constructor_range_stack->next = p; + constructor_range_stack = p; +} + +/* 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 (tree first, tree last, + struct obstack * braced_init_obstack) +{ + if (set_designator (1, braced_init_obstack)) + return; + + designator_erroneous = 1; + + if (!INTEGRAL_TYPE_P (TREE_TYPE (first)) + || (last && !INTEGRAL_TYPE_P (TREE_TYPE (last)))) + { + error_init ("array index in initializer not of integer type"); + return; + } + + if (TREE_CODE (first) != INTEGER_CST) + { + first = c_fully_fold (first, false, NULL); + if (TREE_CODE (first) == INTEGER_CST) + pedwarn_init (input_location, OPT_Wpedantic, + "array index in initializer is not " + "an integer constant expression"); + } + + if (last && TREE_CODE (last) != INTEGER_CST) + { + last = c_fully_fold (last, false, NULL); + if (TREE_CODE (last) == INTEGER_CST) + pedwarn_init (input_location, OPT_Wpedantic, + "array index in initializer is not " + "an integer constant expression"); + } + + 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 (TREE_CODE (constructor_type) != ARRAY_TYPE) + error_init ("array index in non-array initializer"); + else if (tree_int_cst_sgn (first) == -1) + error_init ("array index in initializer exceeds array bounds"); + else if (constructor_max_index + && tree_int_cst_lt (constructor_max_index, first)) + error_init ("array index in initializer exceeds array bounds"); + else + { + constant_expression_warning (first); + if (last) + constant_expression_warning (last); + constructor_index = convert (bitsizetype, first); + + if (last) + { + if (tree_int_cst_equal (first, last)) + last = 0; + else if (tree_int_cst_lt (last, first)) + { + error_init ("empty index range in initializer"); + last = 0; + } + else + { + last = convert (bitsizetype, last); + if (constructor_max_index != 0 + && tree_int_cst_lt (constructor_max_index, last)) + { + error_init ("array index range in initializer exceeds array bounds"); + last = 0; + } + } + } + + designator_depth++; + designator_erroneous = 0; + if (constructor_range_stack || last) + push_range_stack (last, braced_init_obstack); + } +} + +/* Within a struct initializer, specify the next field to be initialized. */ + +void +set_init_label (tree fieldname, struct obstack * braced_init_obstack) +{ + tree field; + + if (set_designator (0, braced_init_obstack)) + return; + + designator_erroneous = 1; + + if (TREE_CODE (constructor_type) != RECORD_TYPE + && TREE_CODE (constructor_type) != UNION_TYPE) + { + error_init ("field name not in record or union initializer"); + return; + } + + field = lookup_field (constructor_type, fieldname); + + if (field == 0) + error ("unknown field %qE specified in initializer", fieldname); + else + do + { + constructor_fields = TREE_VALUE (field); + designator_depth++; + designator_erroneous = 0; + if (constructor_range_stack) + push_range_stack (NULL_TREE, braced_init_obstack); + field = TREE_CHAIN (field); + if (field) + { + if (set_designator (0, braced_init_obstack)) + return; + } + } + while (field != NULL_TREE); +} + +/* Add a new initializer to the tree of pending initializers. PURPOSE + identifies the initializer, either array index or field in a structure. + VALUE is the value of that index or field. If ORIGTYPE is not + NULL_TREE, it is the original type of VALUE. + + IMPLICIT is true if value comes from pop_init_level (1), + the new initializer has been merged with the existing one + and thus no warnings should be emitted about overriding an + existing initializer. */ + +static void +add_pending_init (tree purpose, tree value, tree origtype, bool implicit, + struct obstack * braced_init_obstack) +{ + 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 + { + if (!implicit) + { + if (TREE_SIDE_EFFECTS (p->value)) + warning_init (0, "initialized field with side-effects overwritten"); + else if (warn_override_init) + warning_init (OPT_Woverride_init, "initialized field overwritten"); + } + p->value = value; + p->origtype = origtype; + return; + } + } + } + else + { + tree bitpos; + + bitpos = bit_position (purpose); + while (*q != NULL) + { + p = *q; + if (tree_int_cst_lt (bitpos, bit_position (p->purpose))) + q = &p->left; + else if (p->purpose != purpose) + q = &p->right; + else + { + if (!implicit) + { + if (TREE_SIDE_EFFECTS (p->value)) + warning_init (0, "initialized field with side-effects overwritten"); + else if (warn_override_init) + warning_init (OPT_Woverride_init, "initialized field overwritten"); + } + p->value = value; + p->origtype = origtype; + return; + } + } + } + + r = (struct init_node *) obstack_alloc (braced_init_obstack, + sizeof (struct init_node)); + r->purpose = purpose; + r->value = value; + r->origtype = origtype; + + *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; + } +} + +/* Build AVL tree from a sorted chain. */ + +static void +set_nonincremental_init (struct obstack * braced_init_obstack) +{ + unsigned HOST_WIDE_INT ix; + tree index, value; + + if (TREE_CODE (constructor_type) != RECORD_TYPE + && TREE_CODE (constructor_type) != ARRAY_TYPE) + return; + + FOR_EACH_CONSTRUCTOR_ELT (constructor_elements, ix, index, value) + { + add_pending_init (index, value, NULL_TREE, true, + braced_init_obstack); + } + constructor_elements = 0; + if (TREE_CODE (constructor_type) == RECORD_TYPE) + { + constructor_unfilled_fields = TYPE_FIELDS (constructor_type); + /* Skip any nameless bit fields at the beginning. */ + while (constructor_unfilled_fields != 0 + && DECL_C_BIT_FIELD (constructor_unfilled_fields) + && DECL_NAME (constructor_unfilled_fields) == 0) + constructor_unfilled_fields = TREE_CHAIN (constructor_unfilled_fields); + + } + else if (TREE_CODE (constructor_type) == ARRAY_TYPE) + { + if (TYPE_DOMAIN (constructor_type)) + constructor_unfilled_index + = convert (bitsizetype, + TYPE_MIN_VALUE (TYPE_DOMAIN (constructor_type))); + else + constructor_unfilled_index = bitsize_zero_node; + } + constructor_incremental = 0; +} + +/* Build AVL tree from a string constant. */ + +static void +set_nonincremental_init_from_string (tree str, + struct obstack * braced_init_obstack) +{ + tree value, purpose, type; + HOST_WIDE_INT val[2]; + const char *p, *end; + int byte, wchar_bytes, charwidth, bitpos; + + gcc_assert (TREE_CODE (constructor_type) == ARRAY_TYPE); + + wchar_bytes = TYPE_PRECISION (TREE_TYPE (TREE_TYPE (str))) / BITS_PER_UNIT; + charwidth = TYPE_PRECISION (char_type_node); + type = TREE_TYPE (constructor_type); + p = TREE_STRING_POINTER (str); + end = p + TREE_STRING_LENGTH (str); + + for (purpose = bitsize_zero_node; + p < end && !tree_int_cst_lt (constructor_max_index, purpose); + purpose = size_binop (PLUS_EXPR, purpose, bitsize_one_node)) + { + if (wchar_bytes == 1) + { + val[1] = (unsigned char) *p++; + val[0] = 0; + } + else + { + val[0] = 0; + val[1] = 0; + for (byte = 0; byte < wchar_bytes; byte++) + { + if (BYTES_BIG_ENDIAN) + bitpos = (wchar_bytes - byte - 1) * charwidth; + else + bitpos = byte * charwidth; + val[bitpos < HOST_BITS_PER_WIDE_INT] + |= ((unsigned HOST_WIDE_INT) ((unsigned char) *p++)) + << (bitpos % HOST_BITS_PER_WIDE_INT); + } + } + + if (!TYPE_UNSIGNED (type)) + { + bitpos = ((wchar_bytes - 1) * charwidth) + HOST_BITS_PER_CHAR; + if (bitpos < HOST_BITS_PER_WIDE_INT) + { + if (val[1] & (((HOST_WIDE_INT) 1) << (bitpos - 1))) + { + val[1] |= ((HOST_WIDE_INT) -1) << bitpos; + val[0] = -1; + } + } + else if (bitpos == HOST_BITS_PER_WIDE_INT) + { + if (val[1] < 0) + val[0] = -1; + } + else if (val[0] & (((HOST_WIDE_INT) 1) + << (bitpos - 1 - HOST_BITS_PER_WIDE_INT))) + val[0] |= ((HOST_WIDE_INT) -1) + << (bitpos - HOST_BITS_PER_WIDE_INT); + } + + value = build_int_cst_wide (type, val[1], val[0]); + add_pending_init (purpose, value, NULL_TREE, true, + braced_init_obstack); + } + + constructor_incremental = 0; +} + +/* Return value of FIELD in pending initializer or zero if the field was + not initialized yet. */ + +static tree +find_init_member (tree field, struct obstack * braced_init_obstack) +{ + struct init_node *p; + + if (TREE_CODE (constructor_type) == ARRAY_TYPE) + { + if (constructor_incremental + && tree_int_cst_lt (field, constructor_unfilled_index)) + set_nonincremental_init (braced_init_obstack); + + p = constructor_pending_elts; + while (p) + { + if (tree_int_cst_lt (field, p->purpose)) + p = p->left; + else if (tree_int_cst_lt (p->purpose, field)) + p = p->right; + else + return p->value; + } + } + else if (TREE_CODE (constructor_type) == RECORD_TYPE) + { + tree bitpos = bit_position (field); + + if (constructor_incremental + && (!constructor_unfilled_fields + || tree_int_cst_lt (bitpos, + bit_position (constructor_unfilled_fields)))) + set_nonincremental_init (braced_init_obstack); + + p = constructor_pending_elts; + while (p) + { + if (field == p->purpose) + return p->value; + else if (tree_int_cst_lt (bitpos, bit_position (p->purpose))) + p = p->left; + else + p = p->right; + } + } + else if (TREE_CODE (constructor_type) == UNION_TYPE) + { + if (!VEC_empty (constructor_elt, constructor_elements) + && (VEC_last (constructor_elt, constructor_elements)->index + == field)) + return VEC_last (constructor_elt, constructor_elements)->value; + } + 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. + If ORIGTYPE is not NULL_TREE, it is the original type of VALUE. + 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. + If VALUE is a string constant, STRICT_STRING is true if it is + unparenthesized or we should not warn here for it being parenthesized. + For other types of VALUE, STRICT_STRING is not used. + + 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.) + + IMPLICIT is true if value comes from pop_init_level (1), + the new initializer has been merged with the existing one + and thus no warnings should be emitted about overriding an + existing initializer. */ + +static void +output_init_element (tree value, tree origtype, bool strict_string, tree type, + tree field, int pending, bool implicit, + struct obstack * braced_init_obstack) +{ + tree semantic_type = NULL_TREE; + constructor_elt *celt; + bool maybe_const = true; + bool npc; + + if (type == error_mark_node || value == error_mark_node) + { + constructor_erroneous = 1; + return; + } + if (TREE_CODE (TREE_TYPE (value)) == ARRAY_TYPE + && (TREE_CODE (value) == STRING_CST + || TREE_CODE (value) == COMPOUND_LITERAL_EXPR) + && !(TREE_CODE (value) == STRING_CST + && TREE_CODE (type) == ARRAY_TYPE + && INTEGRAL_TYPE_P (TREE_TYPE (type))) + && !comptypes (TYPE_MAIN_VARIANT (TREE_TYPE (value)), + TYPE_MAIN_VARIANT (type))) + value = array_to_pointer_conversion (input_location, value); + + if (TREE_CODE (value) == COMPOUND_LITERAL_EXPR + && require_constant_value && !flag_isoc99 && pending) + { + /* As an extension, allow initializing objects with static storage + duration with compound literals (which are then treated just as + the brace enclosed list they contain). */ + tree decl = COMPOUND_LITERAL_EXPR_DECL (value); + value = DECL_INITIAL (decl); + } + + npc = null_pointer_constant_p (value); + if (TREE_CODE (value) == EXCESS_PRECISION_EXPR) + { + semantic_type = TREE_TYPE (value); + value = TREE_OPERAND (value, 0); + } + value = c_fully_fold (value, require_constant_value, &maybe_const); + + 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)) + || ((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 (!maybe_const) + constructor_nonconst = 1; + + if (!initializer_constant_valid_p (value, TREE_TYPE (value))) + { + if (require_constant_value) + { + error_init ("initializer element is not constant"); + value = error_mark_node; + } + else if (require_constant_elements) + pedwarn (input_location, 0, + "initializer element is not computable at load time"); + } + else if (!maybe_const + && (require_constant_value || require_constant_elements)) + pedwarn_init (input_location, 0, + "initializer element is not a constant expression"); + + /* Issue -Wc++-compat warnings about initializing a bitfield with + enum type. */ + if (warn_cxx_compat + && field != NULL_TREE + && TREE_CODE (field) == FIELD_DECL + && DECL_BIT_FIELD_TYPE (field) != NULL_TREE + && (TYPE_MAIN_VARIANT (DECL_BIT_FIELD_TYPE (field)) + != TYPE_MAIN_VARIANT (type)) + && TREE_CODE (DECL_BIT_FIELD_TYPE (field)) == ENUMERAL_TYPE) + { + tree checktype = origtype != NULL_TREE ? origtype : TREE_TYPE (value); + if (checktype != error_mark_node + && (TYPE_MAIN_VARIANT (checktype) + != TYPE_MAIN_VARIANT (DECL_BIT_FIELD_TYPE (field)))) + warning_init (OPT_Wc___compat, + "enum conversion in initialization is invalid in C++"); + } + + /* If this field is empty (and not at the end of structure), + don't do anything other than checking the initializer. */ + if (field + && (TREE_TYPE (field) == error_mark_node + || (COMPLETE_TYPE_P (TREE_TYPE (field)) + && integer_zerop (TYPE_SIZE (TREE_TYPE (field))) + && (TREE_CODE (constructor_type) == ARRAY_TYPE + || DECL_CHAIN (field))))) + return; + + if (semantic_type) + value = build1 (EXCESS_PRECISION_EXPR, semantic_type, value); + value = digest_init (input_location, type, value, origtype, npc, + strict_string, require_constant_value); + if (value == error_mark_node) + { + constructor_erroneous = 1; + return; + } + if (require_constant_value || require_constant_elements) + constant_expression_warning (value); + + /* If this element doesn't come next in sequence, + put it on constructor_pending_elts. */ + if (TREE_CODE (constructor_type) == ARRAY_TYPE + && (!constructor_incremental + || !tree_int_cst_equal (field, constructor_unfilled_index))) + { + if (constructor_incremental + && tree_int_cst_lt (field, constructor_unfilled_index)) + set_nonincremental_init (braced_init_obstack); + + add_pending_init (field, value, origtype, implicit, + braced_init_obstack); + return; + } + else if (TREE_CODE (constructor_type) == RECORD_TYPE + && (!constructor_incremental + || 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 (constructor_incremental) + { + if (!constructor_unfilled_fields) + set_nonincremental_init (braced_init_obstack); + else + { + tree bitpos, unfillpos; + + bitpos = bit_position (field); + unfillpos = bit_position (constructor_unfilled_fields); + + if (tree_int_cst_lt (bitpos, unfillpos)) + set_nonincremental_init (braced_init_obstack); + } + } + + add_pending_init (field, value, origtype, implicit, + braced_init_obstack); + return; + } + else if (TREE_CODE (constructor_type) == UNION_TYPE + && !VEC_empty (constructor_elt, constructor_elements)) + { + if (!implicit) + { + if (TREE_SIDE_EFFECTS (VEC_last (constructor_elt, + constructor_elements)->value)) + warning_init (0, + "initialized field with side-effects overwritten"); + else if (warn_override_init) + warning_init (OPT_Woverride_init, "initialized field overwritten"); + } + + /* We can have just one union field set. */ + constructor_elements = 0; + } + + /* Otherwise, output this element either to + constructor_elements or to the assembler file. */ + + celt = VEC_safe_push (constructor_elt, gc, constructor_elements, NULL); + celt->index = field; + celt->value = value; + + /* Advance the variable that indicates sequential elements output. */ + if (TREE_CODE (constructor_type) == ARRAY_TYPE) + constructor_unfilled_index + = size_binop_loc (input_location, PLUS_EXPR, constructor_unfilled_index, + bitsize_one_node); + else if (TREE_CODE (constructor_type) == RECORD_TYPE) + { + constructor_unfilled_fields + = DECL_CHAIN (constructor_unfilled_fields); + + /* Skip any nameless bit fields. */ + while (constructor_unfilled_fields != 0 + && DECL_C_BIT_FIELD (constructor_unfilled_fields) + && DECL_NAME (constructor_unfilled_fields) == 0) + constructor_unfilled_fields = + DECL_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, braced_init_obstack); +} + +/* 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 (int all, struct obstack * braced_init_obstack) +{ + struct init_node *elt = constructor_pending_elts; + tree next; + + retry: + + /* Look through 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, elt->origtype, true, + TREE_TYPE (constructor_type), + constructor_unfilled_index, 0, false, + braced_init_obstack); + 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) + { + tree ctor_unfilled_bitpos, elt_bitpos; + + /* If the current record is complete we are done. */ + if (constructor_unfilled_fields == 0) + break; + + ctor_unfilled_bitpos = bit_position (constructor_unfilled_fields); + elt_bitpos = bit_position (elt->purpose); + /* We can't compare fields here because there might be empty + fields in between. */ + if (tree_int_cst_equal (elt_bitpos, ctor_unfilled_bitpos)) + { + constructor_unfilled_fields = elt->purpose; + output_init_element (elt->value, elt->origtype, true, + TREE_TYPE (elt->purpose), + elt->purpose, 0, false, + braced_init_obstack); + } + else if (tree_int_cst_lt (ctor_unfilled_bitpos, elt_bitpos)) + { + /* 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 (ctor_unfilled_bitpos, + bit_position (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; + + /* 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) + constructor_unfilled_index = 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. + + IMPLICIT is true if value comes from pop_init_level (1), + the new initializer has been merged with the existing one + and thus no warnings should be emitted about overriding an + existing initializer. */ + +void +process_init_element (struct c_expr value, bool implicit, + struct obstack * braced_init_obstack) +{ + tree orig_value = value.value; + int string_flag = orig_value != 0 && TREE_CODE (orig_value) == STRING_CST; + bool strict_string = value.original_code == STRING_CST; + + designator_depth = 0; + designator_erroneous = 0; + + /* Handle superfluous braces around string cst as in + char x[] = {"foo"}; */ + if (string_flag + && constructor_type + && TREE_CODE (constructor_type) == ARRAY_TYPE + && INTEGRAL_TYPE_P (TREE_TYPE (constructor_type)) + && integer_zerop (constructor_unfilled_index)) + { + if (constructor_stack->replacement_value.value) + error_init ("excess elements in char array initializer"); + constructor_stack->replacement_value = value; + return; + } + + if (constructor_stack->replacement_value.value != 0) + { + error_init ("excess elements in struct initializer"); + return; + } + + /* 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, braced_init_obstack), + true, braced_init_obstack); + else if ((TREE_CODE (constructor_type) == ARRAY_TYPE + || TREE_CODE (constructor_type) == VECTOR_TYPE) + && (constructor_max_index == 0 + || tree_int_cst_lt (constructor_max_index, + constructor_index))) + process_init_element (pop_init_level (1, braced_init_obstack), + true, braced_init_obstack); + else + break; + } + + /* In the case of [LO ... HI] = VALUE, only evaluate VALUE once. */ + if (constructor_range_stack) + { + /* If value is a compound literal and we'll be just using its + content, don't put it into a SAVE_EXPR. */ + if (TREE_CODE (value.value) != COMPOUND_LITERAL_EXPR + || !require_constant_value + || flag_isoc99) + { + tree semantic_type = NULL_TREE; + if (TREE_CODE (value.value) == EXCESS_PRECISION_EXPR) + { + semantic_type = TREE_TYPE (value.value); + value.value = TREE_OPERAND (value.value, 0); + } + value.value = c_save_expr (value.value); + if (semantic_type) + value.value = build1 (EXCESS_PRECISION_EXPR, semantic_type, + value.value); + } + } + + while (1) + { + if (TREE_CODE (constructor_type) == RECORD_TYPE) + { + tree fieldtype; + enum tree_code fieldcode; + + if (constructor_fields == 0) + { + pedwarn_init (input_location, 0, + "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); + + /* Error for non-static initialization of a flexible array member. */ + if (fieldcode == ARRAY_TYPE + && !require_constant_value + && TYPE_SIZE (fieldtype) == NULL_TREE + && DECL_CHAIN (constructor_fields) == NULL_TREE) + { + error_init ("non-static initialization of a flexible array member"); + break; + } + + /* Accept a string constant to initialize a subarray. */ + if (value.value != 0 + && fieldcode == ARRAY_TYPE + && INTEGRAL_TYPE_P (TREE_TYPE (fieldtype)) + && string_flag) + value.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.value != 0 + && value.value != error_mark_node + && TYPE_MAIN_VARIANT (TREE_TYPE (value.value)) != fieldtype + && (fieldcode == RECORD_TYPE || fieldcode == ARRAY_TYPE + || fieldcode == UNION_TYPE || fieldcode == VECTOR_TYPE)) + { + push_init_level (1, braced_init_obstack); + continue; + } + + if (value.value) + { + push_member_name (constructor_fields); + output_init_element (value.value, value.original_type, + strict_string, fieldtype, + constructor_fields, 1, implicit, + braced_init_obstack); + 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. */ + if (DECL_SIZE (constructor_fields)) + constructor_bit_index + = size_binop_loc (input_location, PLUS_EXPR, + bit_position (constructor_fields), + DECL_SIZE (constructor_fields)); + + /* If the current field was the first one not yet written out, + it isn't now, so update. */ + if (constructor_unfilled_fields == constructor_fields) + { + constructor_unfilled_fields = DECL_CHAIN (constructor_fields); + /* Skip any nameless bit fields. */ + while (constructor_unfilled_fields != 0 + && DECL_C_BIT_FIELD (constructor_unfilled_fields) + && DECL_NAME (constructor_unfilled_fields) == 0) + constructor_unfilled_fields = + DECL_CHAIN (constructor_unfilled_fields); + } + } + + constructor_fields = DECL_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 = DECL_CHAIN (constructor_fields); + } + else if (TREE_CODE (constructor_type) == UNION_TYPE) + { + tree fieldtype; + enum tree_code fieldcode; + + if (constructor_fields == 0) + { + pedwarn_init (input_location, 0, + "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); + + /* Warn that traditional C rejects initialization of unions. + We skip the warning if the value is zero. This is done + under the assumption that the zero initializer in user + code appears conditioned on e.g. __STDC__ to avoid + "missing initializer" warnings and relies on default + initialization to zero in the traditional C case. + We also skip the warning if the initializer is designated, + again on the assumption that this must be conditional on + __STDC__ anyway (and we've already complained about the + member-designator already). */ + if (!in_system_header && !constructor_designated + && !(value.value && (integer_zerop (value.value) + || real_zerop (value.value)))) + warning (OPT_Wtraditional, "traditional C rejects initialization " + "of unions"); + + /* Accept a string constant to initialize a subarray. */ + if (value.value != 0 + && fieldcode == ARRAY_TYPE + && INTEGRAL_TYPE_P (TREE_TYPE (fieldtype)) + && string_flag) + value.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.value != 0 + && value.value != error_mark_node + && TYPE_MAIN_VARIANT (TREE_TYPE (value.value)) != fieldtype + && (fieldcode == RECORD_TYPE || fieldcode == ARRAY_TYPE + || fieldcode == UNION_TYPE || fieldcode == VECTOR_TYPE)) + { + push_init_level (1, braced_init_obstack); + continue; + } + + if (value.value) + { + push_member_name (constructor_fields); + output_init_element (value.value, value.original_type, + strict_string, fieldtype, + constructor_fields, 1, implicit, + braced_init_obstack); + RESTORE_SPELLING_DEPTH (constructor_depth); + } + else + /* Do the bookkeeping for an element that was + directly output as a constructor. */ + { + constructor_bit_index = DECL_SIZE (constructor_fields); + constructor_unfilled_fields = DECL_CHAIN (constructor_fields); + } + + constructor_fields = 0; + } + else 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.value != 0 + && eltcode == ARRAY_TYPE + && INTEGRAL_TYPE_P (TREE_TYPE (elttype)) + && string_flag) + value.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.value != 0 + && value.value != error_mark_node + && TYPE_MAIN_VARIANT (TREE_TYPE (value.value)) != elttype + && (eltcode == RECORD_TYPE || eltcode == ARRAY_TYPE + || eltcode == UNION_TYPE || eltcode == VECTOR_TYPE)) + { + push_init_level (1, braced_init_obstack); + continue; + } + + if (constructor_max_index != 0 + && (tree_int_cst_lt (constructor_max_index, constructor_index) + || integer_all_onesp (constructor_max_index))) + { + pedwarn_init (input_location, 0, + "excess elements in array initializer"); + break; + } + + /* Now output the actual element. */ + if (value.value) + { + push_array_bounds (tree_low_cst (constructor_index, 1)); + output_init_element (value.value, value.original_type, + strict_string, elttype, + constructor_index, 1, implicit, + braced_init_obstack); + RESTORE_SPELLING_DEPTH (constructor_depth); + } + + constructor_index + = size_binop_loc (input_location, PLUS_EXPR, + constructor_index, bitsize_one_node); + + if (!value.value) + /* If we are doing the bookkeeping for an element that was + directly output as a constructor, we must update + constructor_unfilled_index. */ + constructor_unfilled_index = constructor_index; + } + else if (TREE_CODE (constructor_type) == VECTOR_TYPE) + { + tree elttype = TYPE_MAIN_VARIANT (TREE_TYPE (constructor_type)); + + /* Do a basic check of initializer size. Note that vectors + always have a fixed size derived from their type. */ + if (tree_int_cst_lt (constructor_max_index, constructor_index)) + { + pedwarn_init (input_location, 0, + "excess elements in vector initializer"); + break; + } + + /* Now output the actual element. */ + if (value.value) + { + if (TREE_CODE (value.value) == VECTOR_CST) + elttype = TYPE_MAIN_VARIANT (constructor_type); + output_init_element (value.value, value.original_type, + strict_string, elttype, + constructor_index, 1, implicit, + braced_init_obstack); + } + + constructor_index + = size_binop_loc (input_location, + PLUS_EXPR, constructor_index, bitsize_one_node); + + if (!value.value) + /* If we are doing the bookkeeping for an element that was + directly output as a constructor, we must update + constructor_unfilled_index. */ + constructor_unfilled_index = constructor_index; + } + + /* Handle the sole element allowed in a braced initializer + for a scalar variable. */ + else if (constructor_type != error_mark_node + && constructor_fields == 0) + { + pedwarn_init (input_location, 0, + "excess elements in scalar initializer"); + break; + } + else + { + if (value.value) + output_init_element (value.value, value.original_type, + strict_string, constructor_type, + NULL_TREE, 1, implicit, + braced_init_obstack); + constructor_fields = 0; + } + + /* Handle range initializers either at this level or anywhere higher + in the designator stack. */ + if (constructor_range_stack) + { + struct constructor_range_stack *p, *range_stack; + int finish = 0; + + range_stack = constructor_range_stack; + constructor_range_stack = 0; + while (constructor_stack != range_stack->stack) + { + gcc_assert (constructor_stack->implicit); + process_init_element (pop_init_level (1, + braced_init_obstack), + true, braced_init_obstack); + } + for (p = range_stack; + !p->range_end || tree_int_cst_equal (p->index, p->range_end); + p = p->prev) + { + gcc_assert (constructor_stack->implicit); + process_init_element (pop_init_level (1, braced_init_obstack), + true, braced_init_obstack); + } + + p->index = size_binop_loc (input_location, + PLUS_EXPR, p->index, bitsize_one_node); + if (tree_int_cst_equal (p->index, p->range_end) && !p->prev) + finish = 1; + + while (1) + { + constructor_index = p->index; + constructor_fields = p->fields; + if (finish && p->range_end && p->index == p->range_start) + { + finish = 0; + p->prev = 0; + } + p = p->next; + if (!p) + break; + push_init_level (2, braced_init_obstack); + p->stack = constructor_stack; + if (p->range_end && tree_int_cst_equal (p->index, p->range_end)) + p->index = p->range_start; + } + + if (!finish) + constructor_range_stack = range_stack; + continue; + } + + break; + } + + constructor_range_stack = 0; +} + +/* Build a complete asm-statement, whose components are a CV_QUALIFIER + (guaranteed to be 'volatile' or null) and ARGS (represented using + an ASM_EXPR node). */ +tree +build_asm_stmt (tree cv_qualifier, tree args) +{ + if (!ASM_VOLATILE_P (args) && cv_qualifier) + ASM_VOLATILE_P (args) = 1; + return add_stmt (args); +} + +/* Build an asm-expr, whose components are a STRING, some OUTPUTS, + some INPUTS, and some CLOBBERS. The latter three may be NULL. + SIMPLE indicates whether there was anything at all after the + string in the asm expression -- asm("blah") and asm("blah" : ) + are subtly different. We use a ASM_EXPR node to represent this. */ +tree +build_asm_expr (location_t loc, tree string, tree outputs, tree inputs, + tree clobbers, tree labels, bool simple) +{ + tree tail; + tree args; + int i; + const char *constraint; + const char **oconstraints; + bool allows_mem, allows_reg, is_inout; + int ninputs, noutputs; + + ninputs = list_length (inputs); + noutputs = list_length (outputs); + oconstraints = (const char **) alloca (noutputs * sizeof (const char *)); + + string = resolve_asm_operand_names (string, outputs, inputs, labels); + + /* Remove output conversions that change the type but not the mode. */ + for (i = 0, tail = outputs; tail; ++i, tail = TREE_CHAIN (tail)) + { + tree output = TREE_VALUE (tail); + + /* ??? Really, this should not be here. Users should be using a + proper lvalue, dammit. But there's a long history of using casts + in the output operands. In cases like longlong.h, this becomes a + primitive form of typechecking -- if the cast can be removed, then + the output operand had a type of the proper width; otherwise we'll + get an error. Gross, but ... */ + STRIP_NOPS (output); + + if (!lvalue_or_else (loc, output, lv_asm)) + output = error_mark_node; + + if (output != error_mark_node + && (TREE_READONLY (output) + || TYPE_READONLY (TREE_TYPE (output)) + || ((TREE_CODE (TREE_TYPE (output)) == RECORD_TYPE + || TREE_CODE (TREE_TYPE (output)) == UNION_TYPE) + && C_TYPE_FIELDS_READONLY (TREE_TYPE (output))))) + readonly_error (output, lv_asm); + + constraint = TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (tail))); + oconstraints[i] = constraint; + + if (parse_output_constraint (&constraint, i, ninputs, noutputs, + &allows_mem, &allows_reg, &is_inout)) + { + /* If the operand is going to end up in memory, + mark it addressable. */ + if (!allows_reg && !c_mark_addressable (output)) + output = error_mark_node; + if (!(!allows_reg && allows_mem) + && output != error_mark_node + && VOID_TYPE_P (TREE_TYPE (output))) + { + error_at (loc, "invalid use of void expression"); + output = error_mark_node; + } + } + else + output = error_mark_node; + + TREE_VALUE (tail) = output; + } + + for (i = 0, tail = inputs; tail; ++i, tail = TREE_CHAIN (tail)) + { + tree input; + + constraint = TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (tail))); + input = TREE_VALUE (tail); + + if (parse_input_constraint (&constraint, i, ninputs, noutputs, 0, + oconstraints, &allows_mem, &allows_reg)) + { + /* If the operand is going to end up in memory, + mark it addressable. */ + if (!allows_reg && allows_mem) + { + /* Strip the nops as we allow this case. FIXME, this really + should be rejected or made deprecated. */ + STRIP_NOPS (input); + if (!c_mark_addressable (input)) + input = error_mark_node; + } + else if (input != error_mark_node && VOID_TYPE_P (TREE_TYPE (input))) + { + error_at (loc, "invalid use of void expression"); + input = error_mark_node; + } + } + else + input = error_mark_node; + + TREE_VALUE (tail) = input; + } + + /* ASMs with labels cannot have outputs. This should have been + enforced by the parser. */ + gcc_assert (outputs == NULL || labels == NULL); + + args = build_stmt (loc, ASM_EXPR, string, outputs, inputs, clobbers, labels); + + /* asm statements without outputs, including simple ones, are treated + as volatile. */ + ASM_INPUT_P (args) = simple; + ASM_VOLATILE_P (args) = (noutputs == 0); + + return args; +} + +/* Generate a goto statement to LABEL. LOC is the location of the + GOTO. */ + +tree +c_finish_goto_label (location_t loc, tree label) +{ + tree decl = lookup_label_for_goto (loc, label); + if (!decl) + return NULL_TREE; + TREE_USED (decl) = 1; + { + tree t = build1 (GOTO_EXPR, void_type_node, decl); + SET_EXPR_LOCATION (t, loc); + return add_stmt (t); + } +} + +/* Generate a computed goto statement to EXPR. LOC is the location of + the GOTO. */ + +tree +c_finish_goto_ptr (location_t loc, tree expr) +{ + tree t; + pedwarn (loc, OPT_Wpedantic, "ISO C forbids %<goto *expr;%>"); + expr = c_fully_fold (expr, false, NULL); + expr = convert (ptr_type_node, expr); + t = build1 (GOTO_EXPR, void_type_node, expr); + SET_EXPR_LOCATION (t, loc); + return add_stmt (t); +} + +/* Generate a C `return' statement. RETVAL is the expression for what + to return, or a null pointer for `return;' with no value. LOC is + the location of the return statement. If ORIGTYPE is not NULL_TREE, it + is the original type of RETVAL. */ + +tree +c_finish_return (location_t loc, tree retval, tree origtype) +{ + tree valtype = TREE_TYPE (TREE_TYPE (current_function_decl)), ret_stmt; + bool no_warning = false; + bool npc = false; + + if (TREE_THIS_VOLATILE (current_function_decl)) + warning_at (loc, 0, + "function declared %<noreturn%> has a %<return%> statement"); + + if (retval) + { + tree semantic_type = NULL_TREE; + npc = null_pointer_constant_p (retval); + if (TREE_CODE (retval) == EXCESS_PRECISION_EXPR) + { + semantic_type = TREE_TYPE (retval); + retval = TREE_OPERAND (retval, 0); + } + retval = c_fully_fold (retval, false, NULL); + if (semantic_type) + retval = build1 (EXCESS_PRECISION_EXPR, semantic_type, retval); + } + + if (!retval) + { + current_function_returns_null = 1; + if ((warn_return_type || flag_isoc99) + && valtype != 0 && TREE_CODE (valtype) != VOID_TYPE) + { + pedwarn_c99 (loc, flag_isoc99 ? 0 : OPT_Wreturn_type, + "%<return%> with no value, in " + "function returning non-void"); + no_warning = true; + } + } + else if (valtype == 0 || TREE_CODE (valtype) == VOID_TYPE) + { + current_function_returns_null = 1; + if (TREE_CODE (TREE_TYPE (retval)) != VOID_TYPE) + pedwarn (loc, 0, + "%<return%> with a value, in function returning void"); + else + pedwarn (loc, OPT_Wpedantic, "ISO C forbids " + "%<return%> with expression, in function returning void"); + } + else + { + tree t = convert_for_assignment (loc, valtype, retval, origtype, + ic_return, + npc, NULL_TREE, NULL_TREE, 0); + tree res = DECL_RESULT (current_function_decl); + tree inner; + + current_function_returns_value = 1; + if (t == error_mark_node) + return NULL_TREE; + + 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_CONVERT: + case NON_LVALUE_EXPR: + case PLUS_EXPR: + case POINTER_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)) + && (CONVERT_EXPR_P (op1) + || TREE_CODE (op1) == NON_LVALUE_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 (REFERENCE_CLASS_P (inner) + && TREE_CODE (inner) != INDIRECT_REF) + inner = TREE_OPERAND (inner, 0); + + if (DECL_P (inner) + && !DECL_EXTERNAL (inner) + && !TREE_STATIC (inner) + && DECL_CONTEXT (inner) == current_function_decl) + warning_at (loc, + 0, "function returns address of local variable"); + break; + + default: + break; + } + + break; + } + + retval = build2 (MODIFY_EXPR, TREE_TYPE (res), res, t); + SET_EXPR_LOCATION (retval, loc); + + if (warn_sequence_point) + verify_sequence_points (retval); + } + + ret_stmt = build_stmt (loc, RETURN_EXPR, retval); + TREE_NO_WARNING (ret_stmt) |= no_warning; + return add_stmt (ret_stmt); +} + +struct c_switch { + /* The SWITCH_EXPR being built. */ + tree switch_expr; + + /* The original type of the testing expression, i.e. before the + default conversion is applied. */ + tree orig_type; + + /* A splay-tree mapping the low element of a case range to the high + element, or NULL_TREE if there is no high element. Used to + determine whether or not a new case label duplicates an old case + label. We need a tree, rather than simply a hash table, because + of the GNU case range extension. */ + splay_tree cases; + + /* The bindings at the point of the switch. This is used for + warnings crossing decls when branching to a case label. */ + struct c_spot_bindings *bindings; + + /* The next node on the stack. */ + struct c_switch *next; +}; + +/* A stack of the currently active switch statements. The innermost + switch statement is on the top of the stack. There is no need to + mark the stack for garbage collection because it is only active + during the processing of the body of a function, and we never + collect at that point. */ + +struct c_switch *c_switch_stack; + +/* Start a C switch statement, testing expression EXP. Return the new + SWITCH_EXPR. SWITCH_LOC is the location of the `switch'. + SWITCH_COND_LOC is the location of the switch's condition. */ + +tree +c_start_case (location_t switch_loc, + location_t switch_cond_loc, + tree exp) +{ + tree orig_type = error_mark_node; + struct c_switch *cs; + + if (exp != error_mark_node) + { + orig_type = TREE_TYPE (exp); + + if (!INTEGRAL_TYPE_P (orig_type)) + { + if (orig_type != error_mark_node) + { + error_at (switch_cond_loc, "switch quantity not an integer"); + orig_type = error_mark_node; + } + exp = integer_zero_node; + } + else + { + tree type = TYPE_MAIN_VARIANT (orig_type); + + if (!in_system_header + && (type == long_integer_type_node + || type == long_unsigned_type_node)) + warning_at (switch_cond_loc, + OPT_Wtraditional, "%<long%> switch expression not " + "converted to %<int%> in ISO C"); + + exp = c_fully_fold (exp, false, NULL); + exp = default_conversion (exp); + + if (warn_sequence_point) + verify_sequence_points (exp); + } + } + + /* Add this new SWITCH_EXPR to the stack. */ + cs = XNEW (struct c_switch); + cs->switch_expr = build3 (SWITCH_EXPR, orig_type, exp, NULL_TREE, NULL_TREE); + SET_EXPR_LOCATION (cs->switch_expr, switch_loc); + cs->orig_type = orig_type; + cs->cases = splay_tree_new (case_compare, NULL, NULL); + cs->bindings = c_get_switch_bindings (); + cs->next = c_switch_stack; + c_switch_stack = cs; + + return add_stmt (cs->switch_expr); +} + +/* Process a case label at location LOC. */ + +tree +do_case (location_t loc, tree low_value, tree high_value) +{ + tree label = NULL_TREE; + + if (low_value && TREE_CODE (low_value) != INTEGER_CST) + { + low_value = c_fully_fold (low_value, false, NULL); + if (TREE_CODE (low_value) == INTEGER_CST) + pedwarn (input_location, OPT_Wpedantic, + "case label is not an integer constant expression"); + } + + if (high_value && TREE_CODE (high_value) != INTEGER_CST) + { + high_value = c_fully_fold (high_value, false, NULL); + if (TREE_CODE (high_value) == INTEGER_CST) + pedwarn (input_location, OPT_Wpedantic, + "case label is not an integer constant expression"); + } + + if (c_switch_stack == NULL) + { + if (low_value) + error_at (loc, "case label not within a switch statement"); + else + error_at (loc, "%<default%> label not within a switch statement"); + return NULL_TREE; + } + + if (c_check_switch_jump_warnings (c_switch_stack->bindings, + EXPR_LOCATION (c_switch_stack->switch_expr), + loc)) + return NULL_TREE; + + label = c_add_case_label (loc, c_switch_stack->cases, + SWITCH_COND (c_switch_stack->switch_expr), + c_switch_stack->orig_type, + low_value, high_value); + if (label == error_mark_node) + label = NULL_TREE; + return label; +} + +/* Finish the switch statement. */ + +void +c_finish_case (tree body) +{ + struct c_switch *cs = c_switch_stack; + location_t switch_location; + + SWITCH_BODY (cs->switch_expr) = body; + + /* Emit warnings as needed. */ + switch_location = EXPR_LOCATION (cs->switch_expr); + c_do_switch_warnings (cs->cases, switch_location, + TREE_TYPE (cs->switch_expr), + SWITCH_COND (cs->switch_expr)); + + /* Pop the stack. */ + c_switch_stack = cs->next; + splay_tree_delete (cs->cases); + c_release_switch_bindings (cs->bindings); + XDELETE (cs); +} + +/* Emit an if statement. IF_LOCUS is the location of the 'if'. COND, + THEN_BLOCK and ELSE_BLOCK are expressions to be used; ELSE_BLOCK + may be null. NESTED_IF is true if THEN_BLOCK contains another IF + statement, and was not surrounded with parenthesis. */ + +void +c_finish_if_stmt (location_t if_locus, tree cond, tree then_block, + tree else_block, bool nested_if) +{ + tree stmt; + + /* Diagnose an ambiguous else if if-then-else is nested inside if-then. */ + if (warn_parentheses && nested_if && else_block == NULL) + { + tree inner_if = then_block; + + /* We know from the grammar productions that there is an IF nested + within THEN_BLOCK. Due to labels and c99 conditional declarations, + it might not be exactly THEN_BLOCK, but should be the last + non-container statement within. */ + while (1) + switch (TREE_CODE (inner_if)) + { + case COND_EXPR: + goto found; + case BIND_EXPR: + inner_if = BIND_EXPR_BODY (inner_if); + break; + case STATEMENT_LIST: + inner_if = expr_last (then_block); + break; + case TRY_FINALLY_EXPR: + case TRY_CATCH_EXPR: + inner_if = TREE_OPERAND (inner_if, 0); + break; + default: + gcc_unreachable (); + } + found: + + if (COND_EXPR_ELSE (inner_if)) + warning_at (if_locus, OPT_Wparentheses, + "suggest explicit braces to avoid ambiguous %<else%>"); + } + + stmt = build3 (COND_EXPR, void_type_node, cond, then_block, else_block); + SET_EXPR_LOCATION (stmt, if_locus); + add_stmt (stmt); +} + +/* Emit a general-purpose loop construct. START_LOCUS is the location of + the beginning of the loop. COND is the loop condition. COND_IS_FIRST + is false for DO loops. INCR is the FOR increment expression. BODY is + the statement controlled by the loop. BLAB is the break label. CLAB is + the continue label. Everything is allowed to be NULL. */ + +void +c_finish_loop (location_t start_locus, tree cond, tree incr, tree body, + tree blab, tree clab, bool cond_is_first) +{ + tree entry = NULL, exit = NULL, t; + + /* If the condition is zero don't generate a loop construct. */ + if (cond && integer_zerop (cond)) + { + if (cond_is_first) + { + t = build_and_jump (&blab); + SET_EXPR_LOCATION (t, start_locus); + add_stmt (t); + } + } + else + { + tree top = build1 (LABEL_EXPR, void_type_node, NULL_TREE); + + /* If we have an exit condition, then we build an IF with gotos either + out of the loop, or to the top of it. If there's no exit condition, + then we just build a jump back to the top. */ + exit = build_and_jump (&LABEL_EXPR_LABEL (top)); + + if (cond && !integer_nonzerop (cond)) + { + /* Canonicalize the loop condition to the end. This means + generating a branch to the loop condition. Reuse the + continue label, if possible. */ + if (cond_is_first) + { + if (incr || !clab) + { + entry = build1 (LABEL_EXPR, void_type_node, NULL_TREE); + t = build_and_jump (&LABEL_EXPR_LABEL (entry)); + } + else + t = build1 (GOTO_EXPR, void_type_node, clab); + SET_EXPR_LOCATION (t, start_locus); + add_stmt (t); + } + + t = build_and_jump (&blab); + if (cond_is_first) + exit = fold_build3_loc (start_locus, + COND_EXPR, void_type_node, cond, exit, t); + else + exit = fold_build3_loc (input_location, + COND_EXPR, void_type_node, cond, exit, t); + } + + add_stmt (top); + } + + if (body) + add_stmt (body); + if (clab) + add_stmt (build1 (LABEL_EXPR, void_type_node, clab)); + if (incr) + add_stmt (incr); + if (entry) + add_stmt (entry); + if (exit) + add_stmt (exit); + if (blab) + add_stmt (build1 (LABEL_EXPR, void_type_node, blab)); +} + +tree +c_finish_bc_stmt (location_t loc, tree *label_p, bool is_break) +{ + bool skip; + tree label = *label_p; + + /* In switch statements break is sometimes stylistically used after + a return statement. This can lead to spurious warnings about + control reaching the end of a non-void function when it is + inlined. Note that we are calling block_may_fallthru with + language specific tree nodes; this works because + block_may_fallthru returns true when given something it does not + understand. */ + skip = !block_may_fallthru (cur_stmt_list); + + if (!label) + { + if (!skip) + *label_p = label = create_artificial_label (loc); + } + else if (TREE_CODE (label) == LABEL_DECL) + ; + else switch (TREE_INT_CST_LOW (label)) + { + case 0: + if (is_break) + error_at (loc, "break statement not within loop or switch"); + else + error_at (loc, "continue statement not within a loop"); + return NULL_TREE; + + case 1: + gcc_assert (is_break); + error_at (loc, "break statement used with OpenMP for loop"); + return NULL_TREE; + + default: + gcc_unreachable (); + } + + if (skip) + return NULL_TREE; + + if (!is_break) + add_stmt (build_predict_expr (PRED_CONTINUE, NOT_TAKEN)); + + return add_stmt (build1 (GOTO_EXPR, void_type_node, label)); +} + +/* A helper routine for c_process_expr_stmt and c_finish_stmt_expr. */ + +static void +emit_side_effect_warnings (location_t loc, tree expr) +{ + if (expr == error_mark_node) + ; + else if (!TREE_SIDE_EFFECTS (expr)) + { + if (!VOID_TYPE_P (TREE_TYPE (expr)) && !TREE_NO_WARNING (expr)) + warning_at (loc, OPT_Wunused_value, "statement with no effect"); + } + else + warn_if_unused_value (expr, loc); +} + +/* Process an expression as if it were a complete statement. Emit + diagnostics, but do not call ADD_STMT. LOC is the location of the + statement. */ + +tree +c_process_expr_stmt (location_t loc, tree expr) +{ + tree exprv; + + if (!expr) + return NULL_TREE; + + expr = c_fully_fold (expr, false, NULL); + + if (warn_sequence_point) + verify_sequence_points (expr); + + if (TREE_TYPE (expr) != error_mark_node + && !COMPLETE_OR_VOID_TYPE_P (TREE_TYPE (expr)) + && TREE_CODE (TREE_TYPE (expr)) != ARRAY_TYPE) + error_at (loc, "expression statement has incomplete type"); + + /* If we're not processing a statement expression, warn about unused values. + Warnings for statement expressions will be emitted later, once we figure + out which is the result. */ + if (!STATEMENT_LIST_STMT_EXPR (cur_stmt_list) + && warn_unused_value) + emit_side_effect_warnings (loc, expr); + + exprv = expr; + while (TREE_CODE (exprv) == COMPOUND_EXPR) + exprv = TREE_OPERAND (exprv, 1); + while (CONVERT_EXPR_P (exprv)) + exprv = TREE_OPERAND (exprv, 0); + if (DECL_P (exprv) + || handled_component_p (exprv) + || TREE_CODE (exprv) == ADDR_EXPR) + mark_exp_read (exprv); + + /* If the expression is not of a type to which we cannot assign a line + number, wrap the thing in a no-op NOP_EXPR. */ + if (DECL_P (expr) || CONSTANT_CLASS_P (expr)) + { + expr = build1 (NOP_EXPR, TREE_TYPE (expr), expr); + SET_EXPR_LOCATION (expr, loc); + } + + return expr; +} + +/* Emit an expression as a statement. LOC is the location of the + expression. */ + +tree +c_finish_expr_stmt (location_t loc, tree expr) +{ + if (expr) + return add_stmt (c_process_expr_stmt (loc, expr)); + else + return NULL; +} + +/* Do the opposite and emit a statement as an expression. To begin, + create a new binding level and return it. */ + +tree +c_begin_stmt_expr (void) +{ + tree ret; + + /* We must force a BLOCK for this level so that, if it is not expanded + later, there is a way to turn off the entire subtree of blocks that + are contained in it. */ + keep_next_level (); + ret = c_begin_compound_stmt (true); + + c_bindings_start_stmt_expr (c_switch_stack == NULL + ? NULL + : c_switch_stack->bindings); + + /* Mark the current statement list as belonging to a statement list. */ + STATEMENT_LIST_STMT_EXPR (ret) = 1; + + return ret; +} + +/* LOC is the location of the compound statement to which this body + belongs. */ + +tree +c_finish_stmt_expr (location_t loc, tree body) +{ + tree last, type, tmp, val; + tree *last_p; + + body = c_end_compound_stmt (loc, body, true); + + c_bindings_end_stmt_expr (c_switch_stack == NULL + ? NULL + : c_switch_stack->bindings); + + /* Locate the last statement in BODY. See c_end_compound_stmt + about always returning a BIND_EXPR. */ + last_p = &BIND_EXPR_BODY (body); + last = BIND_EXPR_BODY (body); + + continue_searching: + if (TREE_CODE (last) == STATEMENT_LIST) + { + tree_stmt_iterator i; + + /* This can happen with degenerate cases like ({ }). No value. */ + if (!TREE_SIDE_EFFECTS (last)) + return body; + + /* If we're supposed to generate side effects warnings, process + all of the statements except the last. */ + if (warn_unused_value) + { + for (i = tsi_start (last); !tsi_one_before_end_p (i); tsi_next (&i)) + { + location_t tloc; + tree t = tsi_stmt (i); + + tloc = EXPR_HAS_LOCATION (t) ? EXPR_LOCATION (t) : loc; + emit_side_effect_warnings (tloc, t); + } + } + else + i = tsi_last (last); + last_p = tsi_stmt_ptr (i); + last = *last_p; + } + + /* If the end of the list is exception related, then the list was split + by a call to push_cleanup. Continue searching. */ + if (TREE_CODE (last) == TRY_FINALLY_EXPR + || TREE_CODE (last) == TRY_CATCH_EXPR) + { + last_p = &TREE_OPERAND (last, 0); + last = *last_p; + goto continue_searching; + } + + if (last == error_mark_node) + return last; + + /* In the case that the BIND_EXPR is not necessary, return the + expression out from inside it. */ + if (last == BIND_EXPR_BODY (body) + && BIND_EXPR_VARS (body) == NULL) + { + /* Even if this looks constant, do not allow it in a constant + expression. */ + last = c_wrap_maybe_const (last, true); + /* Do not warn if the return value of a statement expression is + unused. */ + TREE_NO_WARNING (last) = 1; + return last; + } + + /* Extract the type of said expression. */ + type = TREE_TYPE (last); + + /* If we're not returning a value at all, then the BIND_EXPR that + we already have is a fine expression to return. */ + if (!type || VOID_TYPE_P (type)) + return body; + + /* Now that we've located the expression containing the value, it seems + silly to make voidify_wrapper_expr repeat the process. Create a + temporary of the appropriate type and stick it in a TARGET_EXPR. */ + tmp = create_tmp_var_raw (type, NULL); + + /* Unwrap a no-op NOP_EXPR as added by c_finish_expr_stmt. This avoids + tree_expr_nonnegative_p giving up immediately. */ + val = last; + if (TREE_CODE (val) == NOP_EXPR + && TREE_TYPE (val) == TREE_TYPE (TREE_OPERAND (val, 0))) + val = TREE_OPERAND (val, 0); + + *last_p = build2 (MODIFY_EXPR, void_type_node, tmp, val); + SET_EXPR_LOCATION (*last_p, EXPR_LOCATION (last)); + + { + tree t = build4 (TARGET_EXPR, type, tmp, body, NULL_TREE, NULL_TREE); + SET_EXPR_LOCATION (t, loc); + return t; + } +} + +/* Begin and end compound statements. This is as simple as pushing + and popping new statement lists from the tree. */ + +tree +c_begin_compound_stmt (bool do_scope) +{ + tree stmt = push_stmt_list (); + if (do_scope) + push_scope (); + return stmt; +} + +/* End a compound statement. STMT is the statement. LOC is the + location of the compound statement-- this is usually the location + of the opening brace. */ + +tree +c_end_compound_stmt (location_t loc, tree stmt, bool do_scope) +{ + tree block = NULL; + + if (do_scope) + { + if (c_dialect_objc ()) + objc_clear_super_receiver (); + block = pop_scope (); + } + + stmt = pop_stmt_list (stmt); + stmt = c_build_bind_expr (loc, block, stmt); + + /* If this compound statement is nested immediately inside a statement + expression, then force a BIND_EXPR to be created. Otherwise we'll + do the wrong thing for ({ { 1; } }) or ({ 1; { } }). In particular, + STATEMENT_LISTs merge, and thus we can lose track of what statement + was really last. */ + if (building_stmt_list_p () + && STATEMENT_LIST_STMT_EXPR (cur_stmt_list) + && TREE_CODE (stmt) != BIND_EXPR) + { + stmt = build3 (BIND_EXPR, void_type_node, NULL, stmt, NULL); + TREE_SIDE_EFFECTS (stmt) = 1; + SET_EXPR_LOCATION (stmt, loc); + } + + return stmt; +} + +/* Queue a cleanup. CLEANUP is an expression/statement to be executed + when the current scope is exited. EH_ONLY is true when this is not + meant to apply to normal control flow transfer. */ + +void +push_cleanup (tree decl, tree cleanup, bool eh_only) +{ + enum tree_code code; + tree stmt, list; + bool stmt_expr; + + code = eh_only ? TRY_CATCH_EXPR : TRY_FINALLY_EXPR; + stmt = build_stmt (DECL_SOURCE_LOCATION (decl), code, NULL, cleanup); + add_stmt (stmt); + stmt_expr = STATEMENT_LIST_STMT_EXPR (cur_stmt_list); + list = push_stmt_list (); + TREE_OPERAND (stmt, 0) = list; + STATEMENT_LIST_STMT_EXPR (list) = stmt_expr; +} + +/* Convert scalar to vector for the range of operations. */ +static enum stv_conv +scalar_to_vector (location_t loc, enum tree_code code, tree op0, tree op1) +{ + tree type0 = TREE_TYPE (op0); + tree type1 = TREE_TYPE (op1); + bool integer_only_op = false; + enum stv_conv ret = stv_firstarg; + + gcc_assert (TREE_CODE (type0) == VECTOR_TYPE + || TREE_CODE (type1) == VECTOR_TYPE); + switch (code) + { + case RSHIFT_EXPR: + case LSHIFT_EXPR: + if (TREE_CODE (type0) == INTEGER_TYPE + && TREE_CODE (TREE_TYPE (type1)) == INTEGER_TYPE) + { + if (unsafe_conversion_p (TREE_TYPE (type1), op0, false)) + { + error_at (loc, "conversion of scalar to vector " + "involves truncation"); + return stv_error; + } + else + return stv_firstarg; + } + break; + + case BIT_IOR_EXPR: + case BIT_XOR_EXPR: + case BIT_AND_EXPR: + integer_only_op = true; + /* ... fall through ... */ + + case PLUS_EXPR: + case MINUS_EXPR: + case MULT_EXPR: + case TRUNC_DIV_EXPR: + case TRUNC_MOD_EXPR: + case RDIV_EXPR: + if (TREE_CODE (type0) == VECTOR_TYPE) + { + tree tmp; + ret = stv_secondarg; + /* Swap TYPE0 with TYPE1 and OP0 with OP1 */ + tmp = type0; type0 = type1; type1 = tmp; + tmp = op0; op0 = op1; op1 = tmp; + } + + if (TREE_CODE (type0) == INTEGER_TYPE + && TREE_CODE (TREE_TYPE (type1)) == INTEGER_TYPE) + { + if (unsafe_conversion_p (TREE_TYPE (type1), op0, false)) + { + error_at (loc, "conversion of scalar to vector " + "involves truncation"); + return stv_error; + } + return ret; + } + else if (!integer_only_op + /* Allow integer --> real conversion if safe. */ + && (TREE_CODE (type0) == REAL_TYPE + || TREE_CODE (type0) == INTEGER_TYPE) + && SCALAR_FLOAT_TYPE_P (TREE_TYPE (type1))) + { + if (unsafe_conversion_p (TREE_TYPE (type1), op0, false)) + { + error_at (loc, "conversion of scalar to vector " + "involves truncation"); + return stv_error; + } + return ret; + } + default: + break; + } + + return stv_nothing; +} + +/* Build a binary-operation expression without default conversions. + CODE is the kind of expression to build. + LOCATION is the operator's location. + This function differs from `build' in several ways: + the data type of the result is computed and recorded in it, + warnings are generated if arg data types are invalid, + special handling for addition and subtraction of pointers is known, + and some optimization is done (operations on narrow ints + are done in the narrower type when that gives the same result). + Constant folding is also done before the result is returned. + + Note that the operands will never have enumeral types, or function + or array types, because either they will have the default conversions + performed or they have both just been converted to some other type in which + the arithmetic is to be done. */ + +tree +build_binary_op (location_t location, enum tree_code code, + tree orig_op0, tree orig_op1, int convert_p) +{ + tree type0, type1, orig_type0, orig_type1; + tree eptype; + enum tree_code code0, code1; + tree op0, op1; + tree ret = error_mark_node; + const char *invalid_op_diag; + bool op0_int_operands, op1_int_operands; + bool int_const, int_const_or_overflow, int_operands; + + /* Expression code to give to the expression when it is built. + Normally this is CODE, which is what the caller asked for, + but in some special cases we change it. */ + enum tree_code resultcode = code; + + /* Data type in which the computation is to be performed. + In the simplest cases this is the common type of the arguments. */ + tree result_type = NULL; + + /* When the computation is in excess precision, the type of the + final EXCESS_PRECISION_EXPR. */ + tree semantic_result_type = NULL; + + /* Nonzero means operands have already been type-converted + in whatever way is necessary. + Zero means they need to be converted to RESULT_TYPE. */ + int converted = 0; + + /* Nonzero means create the expression with this type, rather than + RESULT_TYPE. */ + tree build_type = 0; + + /* Nonzero means after finally constructing the expression + convert it to this type. */ + tree final_type = 0; + + /* Nonzero if this is an operation like MIN or MAX which can + safely be computed in short if both args are promoted shorts. + Also implies COMMON. + -1 indicates a bitwise operation; this makes a difference + in the exact conditions for when it is safe to do the operation + in a narrower mode. */ + int shorten = 0; + + /* Nonzero if this is a comparison operation; + if both args are promoted shorts, compare the original shorts. + Also implies COMMON. */ + int short_compare = 0; + + /* Nonzero if this is a right-shift operation, which can be computed on the + original short and then promoted if the operand is a promoted short. */ + int short_shift = 0; + + /* Nonzero means set RESULT_TYPE to the common type of the args. */ + int common = 0; + + /* True means types are compatible as far as ObjC is concerned. */ + bool objc_ok; + + /* True means this is an arithmetic operation that may need excess + precision. */ + bool may_need_excess_precision; + + /* True means this is a boolean operation that converts both its + operands to truth-values. */ + bool boolean_op = false; + + if (location == UNKNOWN_LOCATION) + location = input_location; + + op0 = orig_op0; + op1 = orig_op1; + + op0_int_operands = EXPR_INT_CONST_OPERANDS (orig_op0); + if (op0_int_operands) + op0 = remove_c_maybe_const_expr (op0); + op1_int_operands = EXPR_INT_CONST_OPERANDS (orig_op1); + if (op1_int_operands) + op1 = remove_c_maybe_const_expr (op1); + int_operands = (op0_int_operands && op1_int_operands); + if (int_operands) + { + int_const_or_overflow = (TREE_CODE (orig_op0) == INTEGER_CST + && TREE_CODE (orig_op1) == INTEGER_CST); + int_const = (int_const_or_overflow + && !TREE_OVERFLOW (orig_op0) + && !TREE_OVERFLOW (orig_op1)); + } + else + int_const = int_const_or_overflow = false; + + /* Do not apply default conversion in mixed vector/scalar expression. */ + if (convert_p + && !((TREE_CODE (TREE_TYPE (op0)) == VECTOR_TYPE) + != (TREE_CODE (TREE_TYPE (op1)) == VECTOR_TYPE))) + { + op0 = default_conversion (op0); + op1 = default_conversion (op1); + } + + orig_type0 = type0 = TREE_TYPE (op0); + orig_type1 = type1 = TREE_TYPE (op1); + + /* The expression codes of the data types of the arguments tell us + whether the arguments are integers, floating, pointers, etc. */ + code0 = TREE_CODE (type0); + code1 = TREE_CODE (type1); + + /* Strip NON_LVALUE_EXPRs, etc., since we aren't using as an lvalue. */ + STRIP_TYPE_NOPS (op0); + STRIP_TYPE_NOPS (op1); + + /* If an error was already reported for one of the arguments, + avoid reporting another error. */ + + if (code0 == ERROR_MARK || code1 == ERROR_MARK) + return error_mark_node; + + if ((invalid_op_diag + = targetm.invalid_binary_op (code, type0, type1))) + { + error_at (location, invalid_op_diag); + return error_mark_node; + } + + switch (code) + { + case PLUS_EXPR: + case MINUS_EXPR: + case MULT_EXPR: + case TRUNC_DIV_EXPR: + case CEIL_DIV_EXPR: + case FLOOR_DIV_EXPR: + case ROUND_DIV_EXPR: + case EXACT_DIV_EXPR: + may_need_excess_precision = true; + break; + default: + may_need_excess_precision = false; + break; + } + if (TREE_CODE (op0) == EXCESS_PRECISION_EXPR) + { + op0 = TREE_OPERAND (op0, 0); + type0 = TREE_TYPE (op0); + } + else if (may_need_excess_precision + && (eptype = excess_precision_type (type0)) != NULL_TREE) + { + type0 = eptype; + op0 = convert (eptype, op0); + } + if (TREE_CODE (op1) == EXCESS_PRECISION_EXPR) + { + op1 = TREE_OPERAND (op1, 0); + type1 = TREE_TYPE (op1); + } + else if (may_need_excess_precision + && (eptype = excess_precision_type (type1)) != NULL_TREE) + { + type1 = eptype; + op1 = convert (eptype, op1); + } + + objc_ok = objc_compare_types (type0, type1, -3, NULL_TREE); + + /* In case when one of the operands of the binary operation is + a vector and another is a scalar -- convert scalar to vector. */ + if ((code0 == VECTOR_TYPE) != (code1 == VECTOR_TYPE)) + { + enum stv_conv convert_flag = scalar_to_vector (location, code, op0, op1); + + switch (convert_flag) + { + case stv_error: + return error_mark_node; + case stv_firstarg: + { + bool maybe_const = true; + tree sc; + sc = c_fully_fold (op0, false, &maybe_const); + sc = save_expr (sc); + sc = convert (TREE_TYPE (type1), sc); + op0 = build_vector_from_val (type1, sc); + if (!maybe_const) + op0 = c_wrap_maybe_const (op0, true); + orig_type0 = type0 = TREE_TYPE (op0); + code0 = TREE_CODE (type0); + converted = 1; + break; + } + case stv_secondarg: + { + bool maybe_const = true; + tree sc; + sc = c_fully_fold (op1, false, &maybe_const); + sc = save_expr (sc); + sc = convert (TREE_TYPE (type0), sc); + op1 = build_vector_from_val (type0, sc); + if (!maybe_const) + op1 = c_wrap_maybe_const (op1, true); + orig_type1 = type1 = TREE_TYPE (op1); + code1 = TREE_CODE (type1); + converted = 1; + break; + } + default: + break; + } + } + + switch (code) + { + case PLUS_EXPR: + /* Handle the pointer + int case. */ + if (code0 == POINTER_TYPE && code1 == INTEGER_TYPE) + { + ret = pointer_int_sum (location, PLUS_EXPR, op0, op1); + goto return_build_binary_op; + } + else if (code1 == POINTER_TYPE && code0 == INTEGER_TYPE) + { + ret = pointer_int_sum (location, PLUS_EXPR, op1, op0); + goto return_build_binary_op; + } + else + common = 1; + break; + + case MINUS_EXPR: + /* Subtraction of two similar pointers. + We must subtract them as integers, then divide by object size. */ + if (code0 == POINTER_TYPE && code1 == POINTER_TYPE + && comp_target_types (location, type0, type1)) + { + ret = pointer_diff (location, op0, op1); + goto return_build_binary_op; + } + /* Handle pointer minus int. Just like pointer plus int. */ + else if (code0 == POINTER_TYPE && code1 == INTEGER_TYPE) + { + ret = pointer_int_sum (location, MINUS_EXPR, op0, op1); + goto return_build_binary_op; + } + else + common = 1; + break; + + case MULT_EXPR: + common = 1; + break; + + case TRUNC_DIV_EXPR: + case CEIL_DIV_EXPR: + case FLOOR_DIV_EXPR: + case ROUND_DIV_EXPR: + case EXACT_DIV_EXPR: + warn_for_div_by_zero (location, op1); + + if ((code0 == INTEGER_TYPE || code0 == REAL_TYPE + || code0 == FIXED_POINT_TYPE + || code0 == COMPLEX_TYPE || code0 == VECTOR_TYPE) + && (code1 == INTEGER_TYPE || code1 == REAL_TYPE + || code1 == FIXED_POINT_TYPE + || code1 == COMPLEX_TYPE || code1 == VECTOR_TYPE)) + { + enum tree_code tcode0 = code0, tcode1 = code1; + + if (code0 == COMPLEX_TYPE || code0 == VECTOR_TYPE) + tcode0 = TREE_CODE (TREE_TYPE (TREE_TYPE (op0))); + if (code1 == COMPLEX_TYPE || code1 == VECTOR_TYPE) + tcode1 = TREE_CODE (TREE_TYPE (TREE_TYPE (op1))); + + if (!((tcode0 == INTEGER_TYPE && tcode1 == INTEGER_TYPE) + || (tcode0 == FIXED_POINT_TYPE && tcode1 == FIXED_POINT_TYPE))) + resultcode = RDIV_EXPR; + else + /* 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 = (TYPE_UNSIGNED (TREE_TYPE (orig_op0)) + || (TREE_CODE (op1) == INTEGER_CST + && !integer_all_onesp (op1))); + common = 1; + } + break; + + case BIT_AND_EXPR: + case BIT_IOR_EXPR: + case BIT_XOR_EXPR: + if (code0 == INTEGER_TYPE && code1 == INTEGER_TYPE) + shorten = -1; + /* Allow vector types which are not floating point types. */ + else if (code0 == VECTOR_TYPE + && code1 == VECTOR_TYPE + && !VECTOR_FLOAT_TYPE_P (type0) + && !VECTOR_FLOAT_TYPE_P (type1)) + common = 1; + break; + + case TRUNC_MOD_EXPR: + case FLOOR_MOD_EXPR: + warn_for_div_by_zero (location, op1); + + if (code0 == VECTOR_TYPE && code1 == VECTOR_TYPE + && TREE_CODE (TREE_TYPE (type0)) == INTEGER_TYPE + && TREE_CODE (TREE_TYPE (type1)) == INTEGER_TYPE) + common = 1; + else 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 = (TYPE_UNSIGNED (TREE_TYPE (orig_op0)) + || (TREE_CODE (op1) == INTEGER_CST + && !integer_all_onesp (op1))); + 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 + || code0 == FIXED_POINT_TYPE) + && (code1 == INTEGER_TYPE || code1 == POINTER_TYPE + || code1 == REAL_TYPE || code1 == COMPLEX_TYPE + || code1 == FIXED_POINT_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 = c_common_truthvalue_conversion (location, op0); + op1 = c_common_truthvalue_conversion (location, op1); + converted = 1; + boolean_op = true; + } + if (code == TRUTH_ANDIF_EXPR) + { + int_const_or_overflow = (int_operands + && TREE_CODE (orig_op0) == INTEGER_CST + && (op0 == truthvalue_false_node + || TREE_CODE (orig_op1) == INTEGER_CST)); + int_const = (int_const_or_overflow + && !TREE_OVERFLOW (orig_op0) + && (op0 == truthvalue_false_node + || !TREE_OVERFLOW (orig_op1))); + } + else if (code == TRUTH_ORIF_EXPR) + { + int_const_or_overflow = (int_operands + && TREE_CODE (orig_op0) == INTEGER_CST + && (op0 == truthvalue_true_node + || TREE_CODE (orig_op1) == INTEGER_CST)); + int_const = (int_const_or_overflow + && !TREE_OVERFLOW (orig_op0) + && (op0 == truthvalue_true_node + || !TREE_OVERFLOW (orig_op1))); + } + 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 == VECTOR_TYPE && code1 == INTEGER_TYPE + && TREE_CODE (TREE_TYPE (type0)) == INTEGER_TYPE) + { + result_type = type0; + converted = 1; + } + else if (code0 == VECTOR_TYPE && code1 == VECTOR_TYPE + && TREE_CODE (TREE_TYPE (type0)) == INTEGER_TYPE + && TREE_CODE (TREE_TYPE (type1)) == INTEGER_TYPE + && TYPE_VECTOR_SUBPARTS (type0) == TYPE_VECTOR_SUBPARTS (type1)) + { + result_type = type0; + converted = 1; + } + else if ((code0 == INTEGER_TYPE || code0 == FIXED_POINT_TYPE) + && code1 == INTEGER_TYPE) + { + if (TREE_CODE (op1) == INTEGER_CST) + { + if (tree_int_cst_sgn (op1) < 0) + { + int_const = false; + if (c_inhibit_evaluation_warnings == 0) + warning (0, "right shift count is negative"); + } + else + { + if (!integer_zerop (op1)) + short_shift = 1; + + if (compare_tree_int (op1, TYPE_PRECISION (type0)) >= 0) + { + int_const = false; + if (c_inhibit_evaluation_warnings == 0) + warning (0, "right shift count >= width of type"); + } + } + } + + /* Use the type of the value to be shifted. */ + result_type = type0; + /* Convert the non vector shift-count to an integer, regardless + of size of value being shifted. */ + if (TREE_CODE (TREE_TYPE (op1)) != VECTOR_TYPE + && 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 == VECTOR_TYPE && code1 == INTEGER_TYPE + && TREE_CODE (TREE_TYPE (type0)) == INTEGER_TYPE) + { + result_type = type0; + converted = 1; + } + else if (code0 == VECTOR_TYPE && code1 == VECTOR_TYPE + && TREE_CODE (TREE_TYPE (type0)) == INTEGER_TYPE + && TREE_CODE (TREE_TYPE (type1)) == INTEGER_TYPE + && TYPE_VECTOR_SUBPARTS (type0) == TYPE_VECTOR_SUBPARTS (type1)) + { + result_type = type0; + converted = 1; + } + else if ((code0 == INTEGER_TYPE || code0 == FIXED_POINT_TYPE) + && code1 == INTEGER_TYPE) + { + if (TREE_CODE (op1) == INTEGER_CST) + { + if (tree_int_cst_sgn (op1) < 0) + { + int_const = false; + if (c_inhibit_evaluation_warnings == 0) + warning (0, "left shift count is negative"); + } + + else if (compare_tree_int (op1, TYPE_PRECISION (type0)) >= 0) + { + int_const = false; + if (c_inhibit_evaluation_warnings == 0) + warning (0, "left shift count >= width of type"); + } + } + + /* Use the type of the value to be shifted. */ + result_type = type0; + /* Convert the non vector shift-count to an integer, regardless + of size of value being shifted. */ + if (TREE_CODE (TREE_TYPE (op1)) != VECTOR_TYPE + && 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: + if (code0 == VECTOR_TYPE && code1 == VECTOR_TYPE) + { + tree intt; + if (TREE_TYPE (type0) != TREE_TYPE (type1)) + { + error_at (location, "comparing vectors with different " + "element types"); + return error_mark_node; + } + + if (TYPE_VECTOR_SUBPARTS (type0) != TYPE_VECTOR_SUBPARTS (type1)) + { + error_at (location, "comparing vectors with different " + "number of elements"); + return error_mark_node; + } + + /* Always construct signed integer vector type. */ + intt = c_common_type_for_size (GET_MODE_BITSIZE + (TYPE_MODE (TREE_TYPE (type0))), 0); + result_type = build_opaque_vector_type (intt, + TYPE_VECTOR_SUBPARTS (type0)); + converted = 1; + break; + } + if (FLOAT_TYPE_P (type0) || FLOAT_TYPE_P (type1)) + warning_at (location, + OPT_Wfloat_equal, + "comparing floating point with == or != is unsafe"); + /* 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 == FIXED_POINT_TYPE || code0 == COMPLEX_TYPE) + && (code1 == INTEGER_TYPE || code1 == REAL_TYPE + || code1 == FIXED_POINT_TYPE || code1 == COMPLEX_TYPE)) + short_compare = 1; + else if (code0 == POINTER_TYPE && null_pointer_constant_p (orig_op1)) + { + if (TREE_CODE (op0) == ADDR_EXPR + && decl_with_nonnull_addr_p (TREE_OPERAND (op0, 0))) + { + if (code == EQ_EXPR) + warning_at (location, + OPT_Waddress, + "the comparison will always evaluate as %<false%> " + "for the address of %qD will never be NULL", + TREE_OPERAND (op0, 0)); + else + warning_at (location, + OPT_Waddress, + "the comparison will always evaluate as %<true%> " + "for the address of %qD will never be NULL", + TREE_OPERAND (op0, 0)); + } + result_type = type0; + } + else if (code1 == POINTER_TYPE && null_pointer_constant_p (orig_op0)) + { + if (TREE_CODE (op1) == ADDR_EXPR + && decl_with_nonnull_addr_p (TREE_OPERAND (op1, 0))) + { + if (code == EQ_EXPR) + warning_at (location, + OPT_Waddress, + "the comparison will always evaluate as %<false%> " + "for the address of %qD will never be NULL", + TREE_OPERAND (op1, 0)); + else + warning_at (location, + OPT_Waddress, + "the comparison will always evaluate as %<true%> " + "for the address of %qD will never be NULL", + TREE_OPERAND (op1, 0)); + } + result_type = type1; + } + else if (code0 == POINTER_TYPE && code1 == POINTER_TYPE) + { + tree tt0 = TREE_TYPE (type0); + tree tt1 = TREE_TYPE (type1); + addr_space_t as0 = TYPE_ADDR_SPACE (tt0); + addr_space_t as1 = TYPE_ADDR_SPACE (tt1); + addr_space_t as_common = ADDR_SPACE_GENERIC; + + /* 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 (location, type0, type1)) + result_type = common_pointer_type (type0, type1); + else if (!addr_space_superset (as0, as1, &as_common)) + { + error_at (location, "comparison of pointers to " + "disjoint address spaces"); + return error_mark_node; + } + else if (VOID_TYPE_P (tt0)) + { + if (pedantic && TREE_CODE (tt1) == FUNCTION_TYPE) + pedwarn (location, OPT_Wpedantic, "ISO C forbids " + "comparison of %<void *%> with function pointer"); + } + else if (VOID_TYPE_P (tt1)) + { + if (pedantic && TREE_CODE (tt0) == FUNCTION_TYPE) + pedwarn (location, OPT_Wpedantic, "ISO C forbids " + "comparison of %<void *%> with function pointer"); + } + else + /* Avoid warning about the volatile ObjC EH puts on decls. */ + if (!objc_ok) + pedwarn (location, 0, + "comparison of distinct pointer types lacks a cast"); + + if (result_type == NULL_TREE) + { + int qual = ENCODE_QUAL_ADDR_SPACE (as_common); + result_type = build_pointer_type + (build_qualified_type (void_type_node, qual)); + } + } + else if (code0 == POINTER_TYPE && code1 == INTEGER_TYPE) + { + result_type = type0; + pedwarn (location, 0, "comparison between pointer and integer"); + } + else if (code0 == INTEGER_TYPE && code1 == POINTER_TYPE) + { + result_type = type1; + pedwarn (location, 0, "comparison between pointer and integer"); + } + break; + + case LE_EXPR: + case GE_EXPR: + case LT_EXPR: + case GT_EXPR: + if (code0 == VECTOR_TYPE && code1 == VECTOR_TYPE) + { + tree intt; + if (TREE_TYPE (type0) != TREE_TYPE (type1)) + { + error_at (location, "comparing vectors with different " + "element types"); + return error_mark_node; + } + + if (TYPE_VECTOR_SUBPARTS (type0) != TYPE_VECTOR_SUBPARTS (type1)) + { + error_at (location, "comparing vectors with different " + "number of elements"); + return error_mark_node; + } + + /* Always construct signed integer vector type. */ + intt = c_common_type_for_size (GET_MODE_BITSIZE + (TYPE_MODE (TREE_TYPE (type0))), 0); + result_type = build_opaque_vector_type (intt, + TYPE_VECTOR_SUBPARTS (type0)); + converted = 1; + break; + } + build_type = integer_type_node; + if ((code0 == INTEGER_TYPE || code0 == REAL_TYPE + || code0 == FIXED_POINT_TYPE) + && (code1 == INTEGER_TYPE || code1 == REAL_TYPE + || code1 == FIXED_POINT_TYPE)) + short_compare = 1; + else if (code0 == POINTER_TYPE && code1 == POINTER_TYPE) + { + addr_space_t as0 = TYPE_ADDR_SPACE (TREE_TYPE (type0)); + addr_space_t as1 = TYPE_ADDR_SPACE (TREE_TYPE (type1)); + addr_space_t as_common; + + if (comp_target_types (location, type0, type1)) + { + result_type = common_pointer_type (type0, type1); + if (!COMPLETE_TYPE_P (TREE_TYPE (type0)) + != !COMPLETE_TYPE_P (TREE_TYPE (type1))) + pedwarn (location, 0, + "comparison of complete and incomplete pointers"); + else if (TREE_CODE (TREE_TYPE (type0)) == FUNCTION_TYPE) + pedwarn (location, OPT_Wpedantic, "ISO C forbids " + "ordered comparisons of pointers to functions"); + else if (null_pointer_constant_p (orig_op0) + || null_pointer_constant_p (orig_op1)) + warning_at (location, OPT_Wextra, + "ordered comparison of pointer with null pointer"); + + } + else if (!addr_space_superset (as0, as1, &as_common)) + { + error_at (location, "comparison of pointers to " + "disjoint address spaces"); + return error_mark_node; + } + else + { + int qual = ENCODE_QUAL_ADDR_SPACE (as_common); + result_type = build_pointer_type + (build_qualified_type (void_type_node, qual)); + pedwarn (location, 0, + "comparison of distinct pointer types lacks a cast"); + } + } + else if (code0 == POINTER_TYPE && null_pointer_constant_p (orig_op1)) + { + result_type = type0; + if (pedantic) + pedwarn (location, OPT_Wpedantic, + "ordered comparison of pointer with integer zero"); + else if (extra_warnings) + warning_at (location, OPT_Wextra, + "ordered comparison of pointer with integer zero"); + } + else if (code1 == POINTER_TYPE && null_pointer_constant_p (orig_op0)) + { + result_type = type1; + if (pedantic) + pedwarn (location, OPT_Wpedantic, + "ordered comparison of pointer with integer zero"); + else if (extra_warnings) + warning_at (location, OPT_Wextra, + "ordered comparison of pointer with integer zero"); + } + else if (code0 == POINTER_TYPE && code1 == INTEGER_TYPE) + { + result_type = type0; + pedwarn (location, 0, "comparison between pointer and integer"); + } + else if (code0 == INTEGER_TYPE && code1 == POINTER_TYPE) + { + result_type = type1; + pedwarn (location, 0, "comparison between pointer and integer"); + } + break; + + default: + gcc_unreachable (); + } + + if (code0 == ERROR_MARK || code1 == ERROR_MARK) + return error_mark_node; + + if (code0 == VECTOR_TYPE && code1 == VECTOR_TYPE + && (!tree_int_cst_equal (TYPE_SIZE (type0), TYPE_SIZE (type1)) + || !same_scalar_type_ignoring_signedness (TREE_TYPE (type0), + TREE_TYPE (type1)))) + { + binary_op_error (location, code, type0, type1); + return error_mark_node; + } + + if ((code0 == INTEGER_TYPE || code0 == REAL_TYPE || code0 == COMPLEX_TYPE + || code0 == FIXED_POINT_TYPE || code0 == VECTOR_TYPE) + && + (code1 == INTEGER_TYPE || code1 == REAL_TYPE || code1 == COMPLEX_TYPE + || code1 == FIXED_POINT_TYPE || code1 == VECTOR_TYPE)) + { + bool first_complex = (code0 == COMPLEX_TYPE); + bool second_complex = (code1 == COMPLEX_TYPE); + int none_complex = (!first_complex && !second_complex); + + if (shorten || common || short_compare) + { + result_type = c_common_type (type0, type1); + do_warn_double_promotion (result_type, type0, type1, + "implicit conversion from %qT to %qT " + "to match other operand of binary " + "expression", + location); + if (result_type == error_mark_node) + return error_mark_node; + } + + if (first_complex != second_complex + && (code == PLUS_EXPR + || code == MINUS_EXPR + || code == MULT_EXPR + || (code == TRUNC_DIV_EXPR && first_complex)) + && TREE_CODE (TREE_TYPE (result_type)) == REAL_TYPE + && flag_signed_zeros) + { + /* An operation on mixed real/complex operands must be + handled specially, but the language-independent code can + more easily optimize the plain complex arithmetic if + -fno-signed-zeros. */ + tree real_type = TREE_TYPE (result_type); + tree real, imag; + if (type0 != orig_type0 || type1 != orig_type1) + { + gcc_assert (may_need_excess_precision && common); + semantic_result_type = c_common_type (orig_type0, orig_type1); + } + if (first_complex) + { + if (TREE_TYPE (op0) != result_type) + op0 = convert_and_check (result_type, op0); + if (TREE_TYPE (op1) != real_type) + op1 = convert_and_check (real_type, op1); + } + else + { + if (TREE_TYPE (op0) != real_type) + op0 = convert_and_check (real_type, op0); + if (TREE_TYPE (op1) != result_type) + op1 = convert_and_check (result_type, op1); + } + if (TREE_CODE (op0) == ERROR_MARK || TREE_CODE (op1) == ERROR_MARK) + return error_mark_node; + if (first_complex) + { + op0 = c_save_expr (op0); + real = build_unary_op (EXPR_LOCATION (orig_op0), REALPART_EXPR, + op0, 1); + imag = build_unary_op (EXPR_LOCATION (orig_op0), IMAGPART_EXPR, + op0, 1); + switch (code) + { + case MULT_EXPR: + case TRUNC_DIV_EXPR: + op1 = c_save_expr (op1); + imag = build2 (resultcode, real_type, imag, op1); + /* Fall through. */ + case PLUS_EXPR: + case MINUS_EXPR: + real = build2 (resultcode, real_type, real, op1); + break; + default: + gcc_unreachable(); + } + } + else + { + op1 = c_save_expr (op1); + real = build_unary_op (EXPR_LOCATION (orig_op1), REALPART_EXPR, + op1, 1); + imag = build_unary_op (EXPR_LOCATION (orig_op1), IMAGPART_EXPR, + op1, 1); + switch (code) + { + case MULT_EXPR: + op0 = c_save_expr (op0); + imag = build2 (resultcode, real_type, op0, imag); + /* Fall through. */ + case PLUS_EXPR: + real = build2 (resultcode, real_type, op0, real); + break; + case MINUS_EXPR: + real = build2 (resultcode, real_type, op0, real); + imag = build1 (NEGATE_EXPR, real_type, imag); + break; + default: + gcc_unreachable(); + } + } + ret = build2 (COMPLEX_EXPR, result_type, real, imag); + goto return_build_binary_op; + } + + /* 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) + { + final_type = result_type; + result_type = shorten_binary_op (result_type, op0, op1, + shorten == -1); + } + + /* 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 = TYPE_UNSIGNED (TREE_TYPE (op0)); + + if (TYPE_PRECISION (TREE_TYPE (arg0)) < TYPE_PRECISION (result_type) + && tree_int_cst_sgn (op1) > 0 + /* We can shorten only if the shift count is less than the + number of bits in the smaller type size. */ + && compare_tree_int (op1, TYPE_PRECISION (TREE_TYPE (arg0))) < 0 + /* We cannot drop an unsigned shift after sign-extension. */ + && (!TYPE_UNSIGNED (final_type) || unsigned_arg)) + { + /* Do an unsigned shift if the operand was zero-extended. */ + result_type + = c_common_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) + { + ret = val; + goto return_build_binary_op; + } + + op0 = xop0, op1 = xop1; + converted = 1; + resultcode = xresultcode; + + if (c_inhibit_evaluation_warnings == 0) + { + bool op0_maybe_const = true; + bool op1_maybe_const = true; + tree orig_op0_folded, orig_op1_folded; + + if (in_late_binary_op) + { + orig_op0_folded = orig_op0; + orig_op1_folded = orig_op1; + } + else + { + /* Fold for the sake of possible warnings, as in + build_conditional_expr. This requires the + "original" values to be folded, not just op0 and + op1. */ + c_inhibit_evaluation_warnings++; + op0 = c_fully_fold (op0, require_constant_value, + &op0_maybe_const); + op1 = c_fully_fold (op1, require_constant_value, + &op1_maybe_const); + c_inhibit_evaluation_warnings--; + orig_op0_folded = c_fully_fold (orig_op0, + require_constant_value, + NULL); + orig_op1_folded = c_fully_fold (orig_op1, + require_constant_value, + NULL); + } + + if (warn_sign_compare) + warn_for_sign_compare (location, orig_op0_folded, + orig_op1_folded, op0, op1, + result_type, resultcode); + if (!in_late_binary_op && !int_operands) + { + if (!op0_maybe_const || TREE_CODE (op0) != INTEGER_CST) + op0 = c_wrap_maybe_const (op0, !op0_maybe_const); + if (!op1_maybe_const || TREE_CODE (op1) != INTEGER_CST) + op1 = c_wrap_maybe_const (op1, !op1_maybe_const); + } + } + } + } + + /* 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 (location, code, TREE_TYPE (op0), TREE_TYPE (op1)); + return error_mark_node; + } + + if (build_type == NULL_TREE) + { + build_type = result_type; + if ((type0 != orig_type0 || type1 != orig_type1) + && !boolean_op) + { + gcc_assert (may_need_excess_precision && common); + semantic_result_type = c_common_type (orig_type0, orig_type1); + } + } + + if (!converted) + { + op0 = ep_convert_and_check (result_type, op0, semantic_result_type); + op1 = ep_convert_and_check (result_type, op1, semantic_result_type); + + /* This can happen if one operand has a vector type, and the other + has a different type. */ + if (TREE_CODE (op0) == ERROR_MARK || TREE_CODE (op1) == ERROR_MARK) + return error_mark_node; + } + + /* Treat expressions in initializers specially as they can't trap. */ + if (int_const_or_overflow) + ret = (require_constant_value + ? fold_build2_initializer_loc (location, resultcode, build_type, + op0, op1) + : fold_build2_loc (location, resultcode, build_type, op0, op1)); + else + ret = build2 (resultcode, build_type, op0, op1); + if (final_type != 0) + ret = convert (final_type, ret); + + return_build_binary_op: + gcc_assert (ret != error_mark_node); + if (TREE_CODE (ret) == INTEGER_CST && !TREE_OVERFLOW (ret) && !int_const) + ret = (int_operands + ? note_integer_operands (ret) + : build1 (NOP_EXPR, TREE_TYPE (ret), ret)); + else if (TREE_CODE (ret) != INTEGER_CST && int_operands + && !in_late_binary_op) + ret = note_integer_operands (ret); + if (semantic_result_type) + ret = build1 (EXCESS_PRECISION_EXPR, semantic_result_type, ret); + protected_set_expr_location (ret, location); + return ret; +} + + +/* Convert EXPR to be a truth-value, validating its type for this + purpose. LOCATION is the source location for the expression. */ + +tree +c_objc_common_truthvalue_conversion (location_t location, tree expr) +{ + bool int_const, int_operands; + + switch (TREE_CODE (TREE_TYPE (expr))) + { + case ARRAY_TYPE: + error_at (location, "used array that cannot be converted to pointer where scalar is required"); + return error_mark_node; + + case RECORD_TYPE: + error_at (location, "used struct type value where scalar is required"); + return error_mark_node; + + case UNION_TYPE: + error_at (location, "used union type value where scalar is required"); + return error_mark_node; + + case VOID_TYPE: + error_at (location, "void value not ignored as it ought to be"); + return error_mark_node; + + case FUNCTION_TYPE: + gcc_unreachable (); + + case VECTOR_TYPE: + error_at (location, "used vector type where scalar is required"); + return error_mark_node; + + default: + break; + } + + int_const = (TREE_CODE (expr) == INTEGER_CST && !TREE_OVERFLOW (expr)); + int_operands = EXPR_INT_CONST_OPERANDS (expr); + if (int_operands) + expr = remove_c_maybe_const_expr (expr); + + /* ??? Should we also give an error for vectors rather than leaving + those to give errors later? */ + expr = c_common_truthvalue_conversion (location, expr); + + if (TREE_CODE (expr) == INTEGER_CST && int_operands && !int_const) + { + if (TREE_OVERFLOW (expr)) + return expr; + else + return note_integer_operands (expr); + } + if (TREE_CODE (expr) == INTEGER_CST && !int_const) + return build1 (NOP_EXPR, TREE_TYPE (expr), expr); + return expr; +} + + +/* Convert EXPR to a contained DECL, updating *TC, *TI and *SE as + required. */ + +tree +c_expr_to_decl (tree expr, bool *tc ATTRIBUTE_UNUSED, bool *se) +{ + if (TREE_CODE (expr) == COMPOUND_LITERAL_EXPR) + { + tree decl = COMPOUND_LITERAL_EXPR_DECL (expr); + /* Executing a compound literal inside a function reinitializes + it. */ + if (!TREE_STATIC (decl)) + *se = true; + return decl; + } + else + return expr; +} + +/* Like c_begin_compound_stmt, except force the retention of the BLOCK. */ + +tree +c_begin_omp_parallel (void) +{ + tree block; + + keep_next_level (); + block = c_begin_compound_stmt (true); + + return block; +} + +/* Generate OMP_PARALLEL, with CLAUSES and BLOCK as its compound + statement. LOC is the location of the OMP_PARALLEL. */ + +tree +c_finish_omp_parallel (location_t loc, tree clauses, tree block) +{ + tree stmt; + + block = c_end_compound_stmt (loc, block, true); + + stmt = make_node (OMP_PARALLEL); + TREE_TYPE (stmt) = void_type_node; + OMP_PARALLEL_CLAUSES (stmt) = clauses; + OMP_PARALLEL_BODY (stmt) = block; + SET_EXPR_LOCATION (stmt, loc); + + return add_stmt (stmt); +} + +/* Like c_begin_compound_stmt, except force the retention of the BLOCK. */ + +tree +c_begin_omp_task (void) +{ + tree block; + + keep_next_level (); + block = c_begin_compound_stmt (true); + + return block; +} + +/* Generate OMP_TASK, with CLAUSES and BLOCK as its compound + statement. LOC is the location of the #pragma. */ + +tree +c_finish_omp_task (location_t loc, tree clauses, tree block) +{ + tree stmt; + + block = c_end_compound_stmt (loc, block, true); + + stmt = make_node (OMP_TASK); + TREE_TYPE (stmt) = void_type_node; + OMP_TASK_CLAUSES (stmt) = clauses; + OMP_TASK_BODY (stmt) = block; + SET_EXPR_LOCATION (stmt, loc); + + return add_stmt (stmt); +} + +/* For all elements of CLAUSES, validate them vs OpenMP constraints. + Remove any elements from the list that are invalid. */ + +tree +c_finish_omp_clauses (tree clauses) +{ + bitmap_head generic_head, firstprivate_head, lastprivate_head; + tree c, t, *pc = &clauses; + const char *name; + + bitmap_obstack_initialize (NULL); + bitmap_initialize (&generic_head, &bitmap_default_obstack); + bitmap_initialize (&firstprivate_head, &bitmap_default_obstack); + bitmap_initialize (&lastprivate_head, &bitmap_default_obstack); + + for (pc = &clauses, c = clauses; c ; c = *pc) + { + bool remove = false; + bool need_complete = false; + bool need_implicitly_determined = false; + + switch (OMP_CLAUSE_CODE (c)) + { + case OMP_CLAUSE_SHARED: + name = "shared"; + need_implicitly_determined = true; + goto check_dup_generic; + + case OMP_CLAUSE_PRIVATE: + name = "private"; + need_complete = true; + need_implicitly_determined = true; + goto check_dup_generic; + + case OMP_CLAUSE_REDUCTION: + name = "reduction"; + need_implicitly_determined = true; + t = OMP_CLAUSE_DECL (c); + if (AGGREGATE_TYPE_P (TREE_TYPE (t)) + || POINTER_TYPE_P (TREE_TYPE (t))) + { + error_at (OMP_CLAUSE_LOCATION (c), + "%qE has invalid type for %<reduction%>", t); + remove = true; + } + else if (FLOAT_TYPE_P (TREE_TYPE (t))) + { + enum tree_code r_code = OMP_CLAUSE_REDUCTION_CODE (c); + const char *r_name = NULL; + + switch (r_code) + { + case PLUS_EXPR: + case MULT_EXPR: + case MINUS_EXPR: + case MIN_EXPR: + case MAX_EXPR: + break; + case BIT_AND_EXPR: + r_name = "&"; + break; + case BIT_XOR_EXPR: + r_name = "^"; + break; + case BIT_IOR_EXPR: + r_name = "|"; + break; + case TRUTH_ANDIF_EXPR: + r_name = "&&"; + break; + case TRUTH_ORIF_EXPR: + r_name = "||"; + break; + default: + gcc_unreachable (); + } + if (r_name) + { + error_at (OMP_CLAUSE_LOCATION (c), + "%qE has invalid type for %<reduction(%s)%>", + t, r_name); + remove = true; + } + } + goto check_dup_generic; + + case OMP_CLAUSE_COPYPRIVATE: + name = "copyprivate"; + goto check_dup_generic; + + case OMP_CLAUSE_COPYIN: + name = "copyin"; + t = OMP_CLAUSE_DECL (c); + if (TREE_CODE (t) != VAR_DECL || !DECL_THREAD_LOCAL_P (t)) + { + error_at (OMP_CLAUSE_LOCATION (c), + "%qE must be %<threadprivate%> for %<copyin%>", t); + remove = true; + } + goto check_dup_generic; + + check_dup_generic: + t = OMP_CLAUSE_DECL (c); + if (TREE_CODE (t) != VAR_DECL && TREE_CODE (t) != PARM_DECL) + { + error_at (OMP_CLAUSE_LOCATION (c), + "%qE is not a variable in clause %qs", t, name); + remove = true; + } + else if (bitmap_bit_p (&generic_head, DECL_UID (t)) + || bitmap_bit_p (&firstprivate_head, DECL_UID (t)) + || bitmap_bit_p (&lastprivate_head, DECL_UID (t))) + { + error_at (OMP_CLAUSE_LOCATION (c), + "%qE appears more than once in data clauses", t); + remove = true; + } + else + bitmap_set_bit (&generic_head, DECL_UID (t)); + break; + + case OMP_CLAUSE_FIRSTPRIVATE: + name = "firstprivate"; + t = OMP_CLAUSE_DECL (c); + need_complete = true; + need_implicitly_determined = true; + if (TREE_CODE (t) != VAR_DECL && TREE_CODE (t) != PARM_DECL) + { + error_at (OMP_CLAUSE_LOCATION (c), + "%qE is not a variable in clause %<firstprivate%>", t); + remove = true; + } + else if (bitmap_bit_p (&generic_head, DECL_UID (t)) + || bitmap_bit_p (&firstprivate_head, DECL_UID (t))) + { + error_at (OMP_CLAUSE_LOCATION (c), + "%qE appears more than once in data clauses", t); + remove = true; + } + else + bitmap_set_bit (&firstprivate_head, DECL_UID (t)); + break; + + case OMP_CLAUSE_LASTPRIVATE: + name = "lastprivate"; + t = OMP_CLAUSE_DECL (c); + need_complete = true; + need_implicitly_determined = true; + if (TREE_CODE (t) != VAR_DECL && TREE_CODE (t) != PARM_DECL) + { + error_at (OMP_CLAUSE_LOCATION (c), + "%qE is not a variable in clause %<lastprivate%>", t); + remove = true; + } + else if (bitmap_bit_p (&generic_head, DECL_UID (t)) + || bitmap_bit_p (&lastprivate_head, DECL_UID (t))) + { + error_at (OMP_CLAUSE_LOCATION (c), + "%qE appears more than once in data clauses", t); + remove = true; + } + else + bitmap_set_bit (&lastprivate_head, DECL_UID (t)); + break; + + case OMP_CLAUSE_IF: + case OMP_CLAUSE_NUM_THREADS: + case OMP_CLAUSE_SCHEDULE: + case OMP_CLAUSE_NOWAIT: + case OMP_CLAUSE_ORDERED: + case OMP_CLAUSE_DEFAULT: + case OMP_CLAUSE_UNTIED: + case OMP_CLAUSE_COLLAPSE: + case OMP_CLAUSE_FINAL: + case OMP_CLAUSE_MERGEABLE: + pc = &OMP_CLAUSE_CHAIN (c); + continue; + + default: + gcc_unreachable (); + } + + if (!remove) + { + t = OMP_CLAUSE_DECL (c); + + if (need_complete) + { + t = require_complete_type (t); + if (t == error_mark_node) + remove = true; + } + + if (need_implicitly_determined) + { + const char *share_name = NULL; + + if (TREE_CODE (t) == VAR_DECL && DECL_THREAD_LOCAL_P (t)) + share_name = "threadprivate"; + else switch (c_omp_predetermined_sharing (t)) + { + case OMP_CLAUSE_DEFAULT_UNSPECIFIED: + break; + case OMP_CLAUSE_DEFAULT_SHARED: + /* const vars may be specified in firstprivate clause. */ + if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_FIRSTPRIVATE + && TREE_READONLY (t)) + break; + share_name = "shared"; + break; + case OMP_CLAUSE_DEFAULT_PRIVATE: + share_name = "private"; + break; + default: + gcc_unreachable (); + } + if (share_name) + { + error_at (OMP_CLAUSE_LOCATION (c), + "%qE is predetermined %qs for %qs", + t, share_name, name); + remove = true; + } + } + } + + if (remove) + *pc = OMP_CLAUSE_CHAIN (c); + else + pc = &OMP_CLAUSE_CHAIN (c); + } + + bitmap_obstack_release (NULL); + return clauses; +} + +/* Create a transaction node. */ + +tree +c_finish_transaction (location_t loc, tree block, int flags) +{ + tree stmt = build_stmt (loc, TRANSACTION_EXPR, block); + if (flags & TM_STMT_ATTR_OUTER) + TRANSACTION_EXPR_OUTER (stmt) = 1; + if (flags & TM_STMT_ATTR_RELAXED) + TRANSACTION_EXPR_RELAXED (stmt) = 1; + return add_stmt (stmt); +} + +/* 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 (tree type, int type_quals) +{ + if (type == error_mark_node) + return type; + + if (TREE_CODE (type) == ARRAY_TYPE) + { + tree t; + tree element_type = c_build_qualified_type (TREE_TYPE (type), + type_quals); + + /* See if we already have an identically qualified type. */ + for (t = TYPE_MAIN_VARIANT (type); t; t = TYPE_NEXT_VARIANT (t)) + { + if (TYPE_QUALS (strip_array_types (t)) == type_quals + && TYPE_NAME (t) == TYPE_NAME (type) + && TYPE_CONTEXT (t) == TYPE_CONTEXT (type) + && attribute_list_equal (TYPE_ATTRIBUTES (t), + TYPE_ATTRIBUTES (type))) + break; + } + if (!t) + { + tree domain = TYPE_DOMAIN (type); + + t = build_variant_type_copy (type); + TREE_TYPE (t) = element_type; + + if (TYPE_STRUCTURAL_EQUALITY_P (element_type) + || (domain && TYPE_STRUCTURAL_EQUALITY_P (domain))) + SET_TYPE_STRUCTURAL_EQUALITY (t); + else if (TYPE_CANONICAL (element_type) != element_type + || (domain && TYPE_CANONICAL (domain) != domain)) + { + tree unqualified_canon + = build_array_type (TYPE_CANONICAL (element_type), + domain? TYPE_CANONICAL (domain) + : NULL_TREE); + TYPE_CANONICAL (t) + = c_build_qualified_type (unqualified_canon, type_quals); + } + else + TYPE_CANONICAL (t) = t; + } + return t; + } + + /* 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++. */ + 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; + } + + return build_qualified_type (type, type_quals); +} + +/* Build a VA_ARG_EXPR for the C parser. */ + +tree +c_build_va_arg (location_t loc, tree expr, tree type) +{ + if (warn_cxx_compat && TREE_CODE (type) == ENUMERAL_TYPE) + warning_at (loc, OPT_Wc___compat, + "C++ requires promoted type, not enum type, in %<va_arg%>"); + return build_va_arg (loc, expr, type); +} diff --git a/gcc/c/config-lang.in b/gcc/c/config-lang.in new file mode 100644 index 00000000000..46c7e477471 --- /dev/null +++ b/gcc/c/config-lang.in @@ -0,0 +1,34 @@ +# Top level configure fragment for GNU C - C language. +# Copyright (C) 1994, 1995, 1997, 1998, 2000, 2001, 2002, 2005, 2007, +# 2010, 2012 +# Free Software Foundation, Inc. + +#This file is part of GCC. + +#GCC 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 3, or (at your option) +#any later version. + +#GCC 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 GCC; see the file COPYING3. If not see +#<http://www.gnu.org/licenses/>. + +# Configure looks for the existence of this file to auto-config each language. +# We define several parameters used by configure: +# +# language - name of language as it would appear in $(LANGUAGES) +# compilers - value to add to $(COMPILERS) + +language="c" + +compilers="cc1\$(exeext)" + +target_libs= + +gtfiles="\$(srcdir)/c/c-lang.c \$(srcdir)/c/c-tree.h \$(srcdir)/c/c-decl.c \$(srcdir)/c-family/c-common.c \$(srcdir)/c-family/c-common.h \$(srcdir)/c-family/c-objc.h \$(srcdir)/c-family/c-cppbuiltin.c \$(srcdir)/c-family/c-pragma.h \$(srcdir)/c-family/c-pragma.c \$(srcdir)/c/c-objc-common.c \$(srcdir)/c/c-parser.c \$(srcdir)/c/c-lang.h" diff --git a/gcc/c/gccspec.c b/gcc/c/gccspec.c new file mode 100644 index 00000000000..e1613594fc4 --- /dev/null +++ b/gcc/c/gccspec.c @@ -0,0 +1,108 @@ +/* Specific flags and argument handling of the C front-end. + Copyright (C) 1999, 2001, 2003, 2007, 2010 Free Software Foundation, Inc. + +This file is part of GCC. + +GCC 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 3, or (at your option) any later +version. + +GCC 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 GCC; see the file COPYING3. If not see +<http://www.gnu.org/licenses/>. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "tm.h" +#include "gcc.h" +#include "opts.h" + +/* Filter command line before processing by the gcc driver proper. */ +void +lang_specific_driver (struct cl_decoded_option **in_decoded_options ATTRIBUTE_UNUSED, + unsigned int *in_decoded_options_count ATTRIBUTE_UNUSED, + int *in_added_libraries ATTRIBUTE_UNUSED) +{ + /* Systems which use the NeXT runtime by default should arrange + for the shared libgcc to be used when -fgnu-runtime is passed + through specs. */ +#if defined(ENABLE_SHARED_LIBGCC) && ! NEXT_OBJC_RUNTIME + unsigned int i; + + /* The new argument list will be contained in this. */ + struct cl_decoded_option *new_decoded_options; + + /* True if we should add -shared-libgcc to the command-line. */ + int shared_libgcc = 0; + + /* The total number of arguments with the new stuff. */ + unsigned int argc; + + /* The argument list. */ + struct cl_decoded_option *decoded_options; + + argc = *in_decoded_options_count; + decoded_options = *in_decoded_options; + + for (i = 1; i < argc; i++) + { + switch (decoded_options[i].opt_index) + { + case OPT_static_libgcc: + case OPT_static: + return; + + case OPT_SPECIAL_input_file: + { + const char *file = decoded_options[i].arg; + int len; + + /* If the filename ends in .m or .mi, we are compiling + ObjC and want to pass -shared-libgcc. */ + len = strlen (file); + if ((len > 2 && file[len - 2] == '.' && file[len - 1] == 'm') + || (len > 3 && file[len - 3] == '.' && file[len - 2] == 'm' + && file[len - 1] == 'i')) + shared_libgcc = 1; + } + break; + } + } + + if (shared_libgcc) + { + new_decoded_options = XNEWVEC (struct cl_decoded_option, argc + 1); + + i = 0; + do + { + new_decoded_options[i] = decoded_options[i]; + i++; + } + while (i < argc); + + generate_option (OPT_shared_libgcc, NULL, 1, CL_DRIVER, + &new_decoded_options[i++]); + + *in_decoded_options_count = i; + *in_decoded_options = new_decoded_options; + } +#endif +} + +/* Called before linking. Returns 0 on success and -1 on failure. */ +int +lang_specific_pre_link (void) +{ + return 0; /* Not used for C. */ +} + +/* Number of extra output files that lang_specific_pre_link may generate. */ +int lang_specific_extra_outfiles = 0; /* Not used for C. */ |