summaryrefslogtreecommitdiffstats
path: root/contrib/gcc/c-common.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/gcc/c-common.c')
-rw-r--r--contrib/gcc/c-common.c4527
1 files changed, 2545 insertions, 1982 deletions
diff --git a/contrib/gcc/c-common.c b/contrib/gcc/c-common.c
index 7305b3c6..b5ea608 100644
--- a/contrib/gcc/c-common.c
+++ b/contrib/gcc/c-common.c
@@ -1,6 +1,6 @@
/* Subroutines shared by all languages that are variants of C.
Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000,
- 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
+ 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
This file is part of GCC.
@@ -16,8 +16,8 @@ for more details.
You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING. If not, write to the Free
-Software Foundation, 59 Temple Place - Suite 330, Boston, MA
-02111-1307, USA. */
+Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301, USA. */
#include "config.h"
#include "system.h"
@@ -42,6 +42,12 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
#include "tree-inline.h"
#include "c-tree.h"
#include "toplev.h"
+#include "tree-iterator.h"
+#include "hashtab.h"
+#include "tree-mudflap.h"
+#include "opts.h"
+#include "real.h"
+#include "cgraph.h"
cpp_reader *parse_in; /* Declared in c-pragma.h. */
@@ -55,6 +61,10 @@ cpp_reader *parse_in; /* Declared in c-pragma.h. */
#define SIZE_TYPE "long unsigned int"
#endif
+#ifndef PID_TYPE
+#define PID_TYPE "int"
+#endif
+
#ifndef WCHAR_TYPE
#define WCHAR_TYPE "int"
#endif
@@ -121,6 +131,10 @@ cpp_reader *parse_in; /* Declared in c-pragma.h. */
tree complex_double_type_node;
tree complex_long_double_type_node;
+ tree dfloat32_type_node;
+ tree dfloat64_type_node;
+ tree_dfloat128_type_node;
+
tree intQI_type_node;
tree intHI_type_node;
tree intSI_type_node;
@@ -182,11 +196,6 @@ cpp_reader *parse_in; /* Declared in c-pragma.h. */
*/
tree c_global_trees[CTI_MAX];
-
-/* TRUE if a code represents a statement. The front end init
- langhook should take care of initialization of this array. */
-
-bool statement_code_p[MAX_TREE_CODES];
/* Switches common to the C front ends. */
@@ -211,6 +220,10 @@ char flag_dump_macros;
char flag_dump_includes;
+/* Nonzero means process PCH files while preprocessing. */
+
+bool flag_pch_preprocess;
+
/* The file name to which we should write a precompiled header, or
NULL if no header will be written in this compile. */
@@ -248,78 +261,9 @@ int flag_ms_extensions;
int flag_no_asm;
-/* Nonzero means give string constants the type `const char *', as mandated
- by the standard. */
-
-int flag_const_strings;
-
/* Nonzero means to treat bitfields as signed unless they say `unsigned'. */
int flag_signed_bitfields = 1;
-int explicit_flag_signed_bitfields;
-
-/* Nonzero means warn about pointer casts that can drop a type qualifier
- from the pointer target type. */
-
-int warn_cast_qual;
-
-/* Warn about functions which might be candidates for format attributes. */
-
-int warn_missing_format_attribute;
-
-/* Nonzero means warn about sizeof(function) or addition/subtraction
- of function pointers. */
-
-int warn_pointer_arith;
-
-/* Nonzero means do not warn that K&R style main() is not a function prototype. */
-
-int flag_bsd_no_warn_kr_main;
-
-/* Nonzero means warn for any global function def
- without separate previous prototype decl. */
-
-int warn_missing_prototypes;
-
-/* Warn if adding () is suggested. */
-
-int warn_parentheses;
-
-/* Warn if initializer is not completely bracketed. */
-
-int warn_missing_braces;
-
-/* Warn about comparison of signed and unsigned values.
- If -1, neither -Wsign-compare nor -Wno-sign-compare has been specified
- (in which case -Wextra gets to decide). */
-
-int warn_sign_compare = -1;
-
-/* Nonzero means warn about usage of long long when `-pedantic'. */
-
-int warn_long_long = 1;
-
-/* Nonzero means warn about deprecated conversion from string constant to
- `char *'. */
-
-int warn_write_strings;
-
-/* Nonzero means warn about multiple (redundant) decls for the same single
- variable or function. */
-
-int warn_redundant_decls;
-
-/* Warn about testing equality of floating point numbers. */
-
-int warn_float_equal;
-
-/* Warn about a subscript that has type char. */
-
-int warn_char_subscripts;
-
-/* Warn if a type conversion is done that might have confusing results. */
-
-int warn_conversion;
/* Warn about #pragma directives that are not recognized. */
@@ -330,35 +274,17 @@ int warn_unknown_pragmas; /* Tri state variable. */
int warn_format;
-/* Warn about Y2K problems with strftime formats. */
-
-int warn_format_y2k;
-
-/* Warn about excess arguments to formats. */
+/* Warn about using __null (as NULL in C++) as sentinel. For code compiled
+ with GCC this doesn't matter as __null is guaranteed to have the right
+ size. */
-int warn_format_extra_args;
-
-/* Warn about zero-length formats. */
-
-int warn_format_zero_length;
-
-/* Warn about non-literal format arguments. */
-
-int warn_format_nonliteral;
-
-/* Warn about possible security problems with calls to format functions. */
-
-int warn_format_security;
+int warn_strict_null_sentinel;
/* Zero means that faster, ...NonNil variants of objc_msgSend...
calls will be used in ObjC; passing nil receivers to such calls
will most likely result in crashes. */
int flag_nil_receivers = 1;
-/* Nonzero means that we will allow new ObjC exception syntax (@throw,
- @try, etc.) in source code. */
-int flag_objc_exceptions = 0;
-
/* Nonzero means that code generation will be altered to support
"zero-link" execution. This currently affects ObjC only, but may
affect other languages in the future. */
@@ -368,14 +294,9 @@ int flag_zero_link = 0;
unit. It will inform the ObjC runtime that class definition(s) herein
contained are to replace one(s) previously loaded. */
int flag_replace_objc_classes = 0;
-
-/* C/ObjC language option variables. */
+/* C/ObjC language option variables. */
-/* Nonzero means message about use of implicit function declarations;
- 1 means warning; 2 means error. */
-
-int mesg_implicit_function_declaration = -1;
/* Nonzero means allow type mismatches in conditional expressions;
just make their values `void'. */
@@ -390,75 +311,14 @@ int flag_isoc94;
int flag_isoc99;
-/* Nonzero means allow the BSD kernel printf enhancements. */
-
-int flag_bsd_format;
-
/* Nonzero means that we have builtin functions, and main is an int. */
int flag_hosted = 1;
-/* Nonzero means warn when casting a function call to a type that does
- not match the return type (e.g. (float)sqrt() or (anything*)malloc()
- when there is no previous declaration of sqrt or malloc. */
-
-int warn_bad_function_cast;
-
-/* Warn about traditional constructs whose meanings changed in ANSI C. */
-
-int warn_traditional;
-
-/* Nonzero means warn for a declaration found after a statement. */
-
-int warn_declaration_after_statement;
-
-/* Nonzero means warn for non-prototype function decls
- or non-prototyped defs without previous prototype. */
-
-int warn_strict_prototypes;
-
-/* Nonzero means warn for any global function def
- without separate previous decl. */
-
-int warn_missing_declarations;
-
-/* Nonzero means warn about declarations of objects not at
- file-scope level and about *all* declarations of functions (whether
- or static) not at file-scope level. Note that we exclude
- implicit function declarations. To get warnings about those, use
- -Wimplicit. */
-
-int warn_nested_externs;
-
/* Warn if main is suspicious. */
int warn_main;
-/* Nonzero means warn about possible violations of sequence point rules. */
-
-int warn_sequence_point;
-
-/* Nonzero means warn about uninitialized variable when it is initialized with itself.
- For example: int i = i;, GCC will not warn about this when warn_init_self is nonzero. */
-
-int warn_init_self;
-
-/* Nonzero means to warn about compile-time division by zero. */
-int warn_div_by_zero = 1;
-
-/* Nonzero means warn about use of implicit int. */
-
-int warn_implicit_int;
-
-/* Warn about NULL being passed to argument slots marked as requiring
- non-NULL. */
-
-int warn_nonnull;
-
-/* Warn about old-style parameter declaration. */
-
-int warn_old_style_definition;
-
/* ObjC language option variables. */
@@ -468,43 +328,16 @@ int warn_old_style_definition;
int flag_gen_declaration;
-/* Generate code for GNU or NeXT runtime environment. */
-
-#ifdef NEXT_OBJC_RUNTIME
-int flag_next_runtime = 1;
-#else
-int flag_next_runtime = 0;
-#endif
-
/* Tells the compiler that this is a special run. Do not perform any
compiling, instead we are to test some platform dependent features
and output a C header file with appropriate definitions. */
int print_struct_values;
-/* ???. Undocumented. */
+/* Tells the compiler what is the constant string class for Objc. */
const char *constant_string_class_name;
-/* Warn if multiple methods are seen for the same selector, but with
- different argument types. Performs the check on the whole selector
- table at the end of compilation. */
-
-int warn_selector;
-
-/* Warn if a @selector() is found, and no method with that selector
- has been previously declared. The check is done on each
- @selector() as soon as it is found - so it warns about forward
- declarations. */
-
-int warn_undeclared_selector;
-
-/* Warn if methods required by a protocol are not implemented in the
- class adopting it. When turned off, methods inherited to that
- class are also considered implemented. */
-
-int warn_protocol = 1;
-
/* C++ language option variables. */
@@ -591,10 +424,16 @@ int flag_weak = 1;
int flag_working_directory = -1;
/* Nonzero to use __cxa_atexit, rather than atexit, to register
- destructors for local statics and global objects. */
+ destructors for local statics and global objects. '2' means it has been
+ set nonzero as a default, not by a command-line flag. */
int flag_use_cxa_atexit = DEFAULT_USE_CXA_ATEXIT;
+/* Nonzero to use __cxa_get_exception_ptr in C++ exception-handling
+ code. '2' means it has not been set explicitly on the command line. */
+
+int flag_use_cxa_get_exception_ptr = 2;
+
/* Nonzero means make the default pedwarns warnings instead of errors.
The value of this flag is ignored if -pedantic is specified. */
@@ -607,70 +446,15 @@ int flag_permissive;
int flag_enforce_eh_specs = 1;
-/* Nonzero means warn about things that will change when compiling
- with an ABI-compliant compiler. */
-
-int warn_abi = 0;
+/* Nonzero means to generate thread-safe code for initializing local
+ statics. */
-/* Nonzero means warn about invalid uses of offsetof. */
-
-int warn_invalid_offsetof = 1;
+int flag_threadsafe_statics = 1;
/* Nonzero means warn about implicit declarations. */
int warn_implicit = 1;
-/* Nonzero means warn when all ctors or dtors are private, and the class
- has no friends. */
-
-int warn_ctor_dtor_privacy = 0;
-
-/* Nonzero means warn in function declared in derived class has the
- same name as a virtual in the base class, but fails to match the
- type signature of any virtual function in the base class. */
-
-int warn_overloaded_virtual;
-
-/* Nonzero means warn when declaring a class that has a non virtual
- destructor, when it really ought to have a virtual one. */
-
-int warn_nonvdtor;
-
-/* Nonzero means warn when the compiler will reorder code. */
-
-int warn_reorder;
-
-/* Nonzero means warn when synthesis behavior differs from Cfront's. */
-
-int warn_synth;
-
-/* Nonzero means warn when we convert a pointer to member function
- into a pointer to (void or function). */
-
-int warn_pmf2ptr = 1;
-
-/* Nonzero means warn about violation of some Effective C++ style rules. */
-
-int warn_ecpp;
-
-/* Nonzero means warn where overload resolution chooses a promotion from
- unsigned to signed over a conversion to an unsigned of the same size. */
-
-int warn_sign_promo;
-
-/* Nonzero means warn when an old-style cast is used. */
-
-int warn_old_style_cast;
-
-/* Nonzero means warn when non-templatized friend functions are
- declared within a template */
-
-int warn_nontemplate_friend = 1;
-
-/* Nonzero means complain about deprecated features. */
-
-int warn_deprecated = 1;
-
/* Maximum template instantiation depth. This limit is rather
arbitrary, but it exists to limit the time it takes to notice
infinite template instantiations. */
@@ -685,10 +469,6 @@ tree *ridpointers;
tree (*make_fname_decl) (tree, int);
-/* If non-NULL, the address of a language-specific function that takes
- any action required right before expand_function_end is called. */
-void (*lang_expand_function_end) (void);
-
/* Nonzero means the expression being parsed will never be evaluated.
This is a count, since unevaluated expressions can nest. */
int skip_evaluation;
@@ -715,27 +495,8 @@ const struct fname_var_t fname_vars[] =
};
static int constant_fits_type_p (tree, tree);
-
-/* Keep a stack of if statements. We record the number of compound
- statements seen up to the if keyword, as well as the line number
- and file of the if. If a potentially ambiguous else is seen, that
- fact is recorded; the warning is issued when we can be sure that
- the enclosing if statement does not have an else branch. */
-typedef struct
-{
- int compstmt_count;
- location_t locus;
- int needs_warning;
- tree if_stmt;
-} if_elt;
-
-static if_elt *if_stack;
-
-/* Amount of space in the if statement stack. */
-static int if_stack_space = 0;
-
-/* Stack pointer. */
-static int if_stack_pointer = 0;
+static tree check_case_value (tree);
+static bool check_case_bounds (tree, tree, tree *, tree *);
static tree handle_packed_attribute (tree *, tree, tree, int, bool *);
static tree handle_nocommon_attribute (tree *, tree, tree, int, bool *);
@@ -744,8 +505,13 @@ static tree handle_noreturn_attribute (tree *, tree, tree, int, bool *);
static tree handle_noinline_attribute (tree *, tree, tree, int, bool *);
static tree handle_always_inline_attribute (tree *, tree, tree, int,
bool *);
+static tree handle_gnu_inline_attribute (tree *, tree, tree, int,
+ bool *);
+static tree handle_flatten_attribute (tree *, tree, tree, int, bool *);
static tree handle_used_attribute (tree *, tree, tree, int, bool *);
static tree handle_unused_attribute (tree *, tree, tree, int, bool *);
+static tree handle_externally_visible_attribute (tree *, tree, tree, int,
+ bool *);
static tree handle_const_attribute (tree *, tree, tree, int, bool *);
static tree handle_transparent_union_attribute (tree *, tree, tree,
int, bool *);
@@ -756,6 +522,7 @@ static tree handle_section_attribute (tree *, tree, tree, int, bool *);
static tree handle_aligned_attribute (tree *, tree, tree, int, bool *);
static tree handle_weak_attribute (tree *, tree, tree, int, bool *) ;
static tree handle_alias_attribute (tree *, tree, tree, int, bool *);
+static tree handle_weakref_attribute (tree *, tree, tree, int, bool *) ;
static tree handle_visibility_attribute (tree *, tree, tree, int,
bool *);
static tree handle_tls_model_attribute (tree *, tree, tree, int,
@@ -763,9 +530,11 @@ static tree handle_tls_model_attribute (tree *, tree, tree, int,
static tree handle_no_instrument_function_attribute (tree *, tree,
tree, int, bool *);
static tree handle_malloc_attribute (tree *, tree, tree, int, bool *);
+static tree handle_returns_twice_attribute (tree *, tree, tree, int, bool *);
static tree handle_no_limit_stack_attribute (tree *, tree, tree, int,
bool *);
static tree handle_pure_attribute (tree *, tree, tree, int, bool *);
+static tree handle_novops_attribute (tree *, tree, tree, int, bool *);
static tree handle_deprecated_attribute (tree *, tree, tree, int,
bool *);
static tree handle_vector_size_attribute (tree *, tree, tree, int,
@@ -775,6 +544,7 @@ static tree handle_nothrow_attribute (tree *, tree, tree, int, bool *);
static tree handle_cleanup_attribute (tree *, tree, tree, int, bool *);
static tree handle_warn_unused_result_attribute (tree *, tree, tree, int,
bool *);
+static tree handle_sentinel_attribute (tree *, tree, tree, int, bool *);
static void check_function_nonnull (tree, tree);
static void check_nonnull_arg (void *, tree, unsigned HOST_WIDE_INT);
@@ -805,10 +575,16 @@ const struct attribute_spec c_common_attribute_table[] =
handle_noinline_attribute },
{ "always_inline", 0, 0, true, false, false,
handle_always_inline_attribute },
+ { "gnu_inline", 0, 0, true, false, false,
+ handle_gnu_inline_attribute },
+ { "flatten", 0, 0, true, false, false,
+ handle_flatten_attribute },
{ "used", 0, 0, true, false, false,
handle_used_attribute },
{ "unused", 0, 0, false, false, false,
handle_unused_attribute },
+ { "externally_visible", 0, 0, true, false, false,
+ handle_externally_visible_attribute },
/* The same comments as for noreturn attributes apply to const ones. */
{ "const", 0, 0, true, false, false,
handle_const_attribute },
@@ -828,19 +604,27 @@ const struct attribute_spec c_common_attribute_table[] =
handle_weak_attribute },
{ "alias", 1, 1, true, false, false,
handle_alias_attribute },
+ { "weakref", 0, 1, true, false, false,
+ handle_weakref_attribute },
{ "no_instrument_function", 0, 0, true, false, false,
handle_no_instrument_function_attribute },
{ "malloc", 0, 0, true, false, false,
handle_malloc_attribute },
+ { "returns_twice", 0, 0, true, false, false,
+ handle_returns_twice_attribute },
{ "no_stack_limit", 0, 0, true, false, false,
handle_no_limit_stack_attribute },
{ "pure", 0, 0, true, false, false,
handle_pure_attribute },
+ /* For internal use (marking of builtins) only. The name contains space
+ to prevent its usage in source code. */
+ { "no vops", 0, 0, true, false, false,
+ handle_novops_attribute },
{ "deprecated", 0, 0, false, false, false,
handle_deprecated_attribute },
{ "vector_size", 1, 1, false, true, false,
handle_vector_size_attribute },
- { "visibility", 1, 1, true, false, false,
+ { "visibility", 1, 1, false, false, false,
handle_visibility_attribute },
{ "tls_model", 1, 1, true, false, false,
handle_tls_model_attribute },
@@ -853,6 +637,8 @@ const struct attribute_spec c_common_attribute_table[] =
handle_cleanup_attribute },
{ "warn_unused_result", 0, 0, false, true, true,
handle_warn_unused_result_attribute },
+ { "sentinel", 0, 1, false, true, true,
+ handle_sentinel_attribute },
{ NULL, 0, 0, false, false, false, NULL }
};
@@ -869,131 +655,6 @@ const struct attribute_spec c_common_format_attribute_table[] =
{ NULL, 0, 0, false, false, false, NULL }
};
-/* Record the start of an if-then, and record the start of it
- for ambiguous else detection.
-
- COND is the condition for the if-then statement.
-
- IF_STMT is the statement node that has already been created for
- this if-then statement. It is created before parsing the
- condition to keep line number information accurate. */
-
-void
-c_expand_start_cond (tree cond, int compstmt_count, tree if_stmt)
-{
- /* Make sure there is enough space on the stack. */
- if (if_stack_space == 0)
- {
- if_stack_space = 10;
- if_stack = xmalloc (10 * sizeof (if_elt));
- }
- else if (if_stack_space == if_stack_pointer)
- {
- if_stack_space += 10;
- if_stack = xrealloc (if_stack, if_stack_space * sizeof (if_elt));
- }
-
- IF_COND (if_stmt) = cond;
- add_stmt (if_stmt);
-
- /* Record this if statement. */
- if_stack[if_stack_pointer].compstmt_count = compstmt_count;
- if_stack[if_stack_pointer].locus = input_location;
- if_stack[if_stack_pointer].needs_warning = 0;
- if_stack[if_stack_pointer].if_stmt = if_stmt;
- if_stack_pointer++;
-}
-
-/* Called after the then-clause for an if-statement is processed. */
-
-void
-c_finish_then (void)
-{
- tree if_stmt = if_stack[if_stack_pointer - 1].if_stmt;
- RECHAIN_STMTS (if_stmt, THEN_CLAUSE (if_stmt));
-}
-
-/* Record the end of an if-then. Optionally warn if a nested
- if statement had an ambiguous else clause. */
-
-void
-c_expand_end_cond (void)
-{
- if_stack_pointer--;
- if (if_stack[if_stack_pointer].needs_warning)
- warning ("%Hsuggest explicit braces to avoid ambiguous `else'",
- &if_stack[if_stack_pointer].locus);
- last_expr_type = NULL_TREE;
-}
-
-/* Called between the then-clause and the else-clause
- of an if-then-else. */
-
-void
-c_expand_start_else (void)
-{
- /* An ambiguous else warning must be generated for the enclosing if
- statement, unless we see an else branch for that one, too. */
- if (warn_parentheses
- && if_stack_pointer > 1
- && (if_stack[if_stack_pointer - 1].compstmt_count
- == if_stack[if_stack_pointer - 2].compstmt_count))
- if_stack[if_stack_pointer - 2].needs_warning = 1;
-
- /* Even if a nested if statement had an else branch, it can't be
- ambiguous if this one also has an else. So don't warn in that
- case. Also don't warn for any if statements nested in this else. */
- if_stack[if_stack_pointer - 1].needs_warning = 0;
- if_stack[if_stack_pointer - 1].compstmt_count--;
-}
-
-/* Called after the else-clause for an if-statement is processed. */
-
-void
-c_finish_else (void)
-{
- tree if_stmt = if_stack[if_stack_pointer - 1].if_stmt;
- RECHAIN_STMTS (if_stmt, ELSE_CLAUSE (if_stmt));
-}
-
-/* Begin an if-statement. Returns a newly created IF_STMT if
- appropriate.
-
- Unlike the C++ front-end, we do not call add_stmt here; it is
- probably safe to do so, but I am not very familiar with this
- code so I am being extra careful not to change its behavior
- beyond what is strictly necessary for correctness. */
-
-tree
-c_begin_if_stmt (void)
-{
- tree r;
- r = build_stmt (IF_STMT, NULL_TREE, NULL_TREE, NULL_TREE);
- return r;
-}
-
-/* Begin a while statement. Returns a newly created WHILE_STMT if
- appropriate.
-
- Unlike the C++ front-end, we do not call add_stmt here; it is
- probably safe to do so, but I am not very familiar with this
- code so I am being extra careful not to change its behavior
- beyond what is strictly necessary for correctness. */
-
-tree
-c_begin_while_stmt (void)
-{
- tree r;
- r = build_stmt (WHILE_STMT, NULL_TREE, NULL_TREE);
- return r;
-}
-
-void
-c_finish_while_stmt_cond (tree cond, tree while_stmt)
-{
- WHILE_COND (while_stmt) = cond;
-}
-
/* Push current bindings for the function name VAR_DECLS. */
void
@@ -1008,7 +669,7 @@ start_fname_decls (void)
if (decl)
{
- saved = tree_cons (decl, build_int_2 (ix, 0), saved);
+ saved = tree_cons (decl, build_int_cst (NULL_TREE, ix), saved);
*fname_vars[ix].decl = NULL_TREE;
}
}
@@ -1019,43 +680,30 @@ start_fname_decls (void)
saved_function_name_decls);
}
-/* Finish up the current bindings, adding them into the
- current function's statement tree. This is done by wrapping the
- function's body in a COMPOUND_STMT containing these decls too. This
- must be done _before_ finish_stmt_tree is called. If there is no
- current function, we must be at file scope and no statements are
- involved. Pop the previous bindings. */
+/* Finish up the current bindings, adding them into the current function's
+ statement tree. This must be done _before_ finish_stmt_tree is called.
+ If there is no current function, we must be at file scope and no statements
+ are involved. Pop the previous bindings. */
void
finish_fname_decls (void)
{
unsigned ix;
- tree body = NULL_TREE;
+ tree stmts = NULL_TREE;
tree stack = saved_function_name_decls;
for (; stack && TREE_VALUE (stack); stack = TREE_CHAIN (stack))
- body = chainon (TREE_VALUE (stack), body);
+ append_to_statement_list (TREE_VALUE (stack), &stmts);
- if (body)
+ if (stmts)
{
- /* They were called into existence, so add to statement tree. Add
- the DECL_STMTs inside the outermost scope. */
- tree *p = &DECL_SAVED_TREE (current_function_decl);
- /* Skip the dummy EXPR_STMT and any EH_SPEC_BLOCK. */
- while (TREE_CODE (*p) != COMPOUND_STMT)
- {
- if (TREE_CODE (*p) == EXPR_STMT)
- p = &TREE_CHAIN (*p);
- else
- p = &TREE_OPERAND(*p, 0);
- }
+ tree *bodyp = &DECL_SAVED_TREE (current_function_decl);
- p = &COMPOUND_BODY (*p);
- if (TREE_CODE (*p) == SCOPE_STMT)
- p = &TREE_CHAIN (*p);
+ if (TREE_CODE (*bodyp) == BIND_EXPR)
+ bodyp = &BIND_EXPR_BODY (*bodyp);
- body = chainon (body, *p);
- *p = body;
+ append_to_statement_list_force (*bodyp, &stmts);
+ *bodyp = stmts;
}
for (ix = 0; fname_vars[ix].decl; ix++)
@@ -1079,26 +727,68 @@ finish_fname_decls (void)
}
/* Return the text name of the current function, suitably prettified
- by PRETTY_P. */
+ by PRETTY_P. Return string must be freed by caller. */
const char *
fname_as_string (int pretty_p)
{
const char *name = "top level";
+ char *namep;
int vrb = 2;
- if (! pretty_p)
+ if (!pretty_p)
{
name = "";
vrb = 0;
}
if (current_function_decl)
- name = (*lang_hooks.decl_printable_name) (current_function_decl, vrb);
+ name = lang_hooks.decl_printable_name (current_function_decl, vrb);
+
+ if (c_lex_string_translate)
+ {
+ int len = strlen (name) + 3; /* Two for '"'s. One for NULL. */
+ cpp_string cstr = { 0, 0 }, strname;
+
+ namep = XNEWVEC (char, len);
+ snprintf (namep, len, "\"%s\"", name);
+ strname.text = (unsigned char *) namep;
+ strname.len = len - 1;
+
+ if (cpp_interpret_string (parse_in, &strname, 1, &cstr, false))
+ {
+ XDELETEVEC (namep);
+ return (char *) cstr.text;
+ }
+ }
+ else
+ namep = xstrdup (name);
- return name;
+ return namep;
}
+/* Expand DECL if it declares an entity not handled by the
+ common code. */
+
+int
+c_expand_decl (tree decl)
+{
+ if (TREE_CODE (decl) == VAR_DECL && !TREE_STATIC (decl))
+ {
+ /* Let the back-end know about this variable. */
+ if (!anon_aggr_type_p (TREE_TYPE (decl)))
+ emit_local_var (decl);
+ else
+ expand_anon_union_decl (decl, NULL_TREE,
+ DECL_ANON_UNION_ELEMS (decl));
+ }
+ else
+ return 0;
+
+ return 1;
+}
+
+
/* Return the VAR_DECL for a const char array naming the current
function. If the VAR_DECL has not yet been created, create it
now. RID indicates how it should be formatted and IDENTIFIER_NODE
@@ -1119,33 +809,30 @@ fname_decl (unsigned int rid, tree id)
decl = *fname_vars[ix].decl;
if (!decl)
{
- tree saved_last_tree = last_tree;
/* If a tree is built here, it would normally have the lineno of
the current statement. Later this tree will be moved to the
beginning of the function and this line number will be wrong.
To avoid this problem set the lineno to 0 here; that prevents
it from appearing in the RTL. */
- int saved_lineno = input_line;
+ tree stmts;
+ location_t saved_location = input_location;
+#ifdef USE_MAPPED_LOCATION
+ input_location = UNKNOWN_LOCATION;
+#else
input_line = 0;
+#endif
+ stmts = push_stmt_list ();
decl = (*make_fname_decl) (id, fname_vars[ix].pretty);
- if (last_tree != saved_last_tree)
- {
- /* We created some statement tree for the decl. This belongs
- at the start of the function, so remove it now and reinsert
- it after the function is complete. */
- tree stmts = TREE_CHAIN (saved_last_tree);
-
- TREE_CHAIN (saved_last_tree) = NULL_TREE;
- last_tree = saved_last_tree;
- saved_function_name_decls = tree_cons (decl, stmts,
- saved_function_name_decls);
- }
+ stmts = pop_stmt_list (stmts);
+ if (!IS_EMPTY_STMT (stmts))
+ saved_function_name_decls
+ = tree_cons (decl, stmts, saved_function_name_decls);
*fname_vars[ix].decl = decl;
- input_line = saved_lineno;
+ input_location = saved_location;
}
if (!ix && !current_function_decl)
- pedwarn ("'%D' is not defined outside of function scope", decl);
+ pedwarn ("%qD is not defined outside of function scope", decl);
return decl;
}
@@ -1157,37 +844,56 @@ fix_string_type (tree value)
{
const int wchar_bytes = TYPE_PRECISION (wchar_type_node) / BITS_PER_UNIT;
const int wide_flag = TREE_TYPE (value) == wchar_array_type_node;
- const int nchars_max = flag_isoc99 ? 4095 : 509;
int length = TREE_STRING_LENGTH (value);
int nchars;
+ tree e_type, i_type, a_type;
/* Compute the number of elements, for the array type. */
nchars = wide_flag ? length / wchar_bytes : length;
- if (pedantic && nchars - 1 > nchars_max && !c_dialect_cxx ())
- pedwarn ("string length `%d' is greater than the length `%d' ISO C%d compilers are required to support",
- nchars - 1, nchars_max, flag_isoc99 ? 99 : 89);
-
- /* Create the array type for the string constant.
- -Wwrite-strings says make the string constant an array of const char
- so that copying it to a non-const pointer will get a warning.
- For C++, this is the standard behavior. */
- if (flag_const_strings && ! flag_writable_strings)
- {
- tree elements
- = build_type_variant (wide_flag ? wchar_type_node : char_type_node,
- 1, 0);
- TREE_TYPE (value)
- = build_array_type (elements,
- build_index_type (build_int_2 (nchars - 1, 0)));
- }
- else
- TREE_TYPE (value)
- = build_array_type (wide_flag ? wchar_type_node : char_type_node,
- build_index_type (build_int_2 (nchars - 1, 0)));
-
+ /* C89 2.2.4.1, C99 5.2.4.1 (Translation limits). The analogous
+ limit in C++98 Annex B is very large (65536) and is not normative,
+ so we do not diagnose it (warn_overlength_strings is forced off
+ in c_common_post_options). */
+ if (warn_overlength_strings)
+ {
+ const int nchars_max = flag_isoc99 ? 4095 : 509;
+ const int relevant_std = flag_isoc99 ? 99 : 90;
+ if (nchars - 1 > nchars_max)
+ /* Translators: The %d after 'ISO C' will be 90 or 99. Do not
+ separate the %d from the 'C'. 'ISO' should not be
+ translated, but it may be moved after 'C%d' in languages
+ where modifiers follow nouns. */
+ pedwarn ("string length %qd is greater than the length %qd "
+ "ISO C%d compilers are required to support",
+ nchars - 1, nchars_max, relevant_std);
+ }
+
+ /* Create the array type for the string constant. The ISO C++
+ standard says that a string literal has type `const char[N]' or
+ `const wchar_t[N]'. We use the same logic when invoked as a C
+ front-end with -Wwrite-strings.
+ ??? We should change the type of an expression depending on the
+ state of a warning flag. We should just be warning -- see how
+ this is handled in the C++ front-end for the deprecated implicit
+ conversion from string literals to `char*' or `wchar_t*'.
+
+ The C++ front end relies on TYPE_MAIN_VARIANT of a cv-qualified
+ array type being the unqualified version of that type.
+ Therefore, if we are constructing an array of const char, we must
+ construct the matching unqualified array type first. The C front
+ end does not require this, but it does no harm, so we do it
+ unconditionally. */
+ e_type = wide_flag ? wchar_type_node : char_type_node;
+ i_type = build_index_type (build_int_cst (NULL_TREE, nchars - 1));
+ a_type = build_array_type (e_type, i_type);
+ if (c_dialect_cxx() || warn_write_strings)
+ a_type = c_build_qualified_type (a_type, TYPE_QUAL_CONST);
+
+ TREE_TYPE (value) = a_type;
TREE_CONSTANT (value) = 1;
- TREE_READONLY (value) = ! flag_writable_strings;
+ TREE_INVARIANT (value) = 1;
+ TREE_READONLY (value) = 1;
TREE_STATIC (value) = 1;
return value;
}
@@ -1204,7 +910,9 @@ constant_expression_warning (tree value)
if ((TREE_CODE (value) == INTEGER_CST || TREE_CODE (value) == REAL_CST
|| TREE_CODE (value) == VECTOR_CST
|| TREE_CODE (value) == COMPLEX_CST)
- && TREE_CONSTANT_OVERFLOW (value) && pedantic)
+ && TREE_CONSTANT_OVERFLOW (value)
+ && warn_overflow
+ && pedantic)
pedwarn ("overflow in constant expression");
}
@@ -1225,7 +933,7 @@ overflow_warning (tree value)
{
TREE_OVERFLOW (value) = 0;
if (skip_evaluation == 0)
- warning ("integer overflow in expression");
+ warning (OPT_Woverflow, "integer overflow in expression");
}
else if ((TREE_CODE (value) == REAL_CST
|| (TREE_CODE (value) == COMPLEX_CST
@@ -1234,13 +942,13 @@ overflow_warning (tree value)
{
TREE_OVERFLOW (value) = 0;
if (skip_evaluation == 0)
- warning ("floating point overflow in expression");
+ warning (OPT_Woverflow, "floating point overflow in expression");
}
else if (TREE_CODE (value) == VECTOR_CST && TREE_OVERFLOW (value))
{
TREE_OVERFLOW (value) = 0;
if (skip_evaluation == 0)
- warning ("vector overflow in expression");
+ warning (OPT_Woverflow, "vector overflow in expression");
}
}
@@ -1249,25 +957,93 @@ overflow_warning (tree value)
Invoke this function on every expression that might be implicitly
converted to an unsigned type. */
-void
+static void
unsigned_conversion_warning (tree result, tree operand)
{
tree type = TREE_TYPE (result);
if (TREE_CODE (operand) == INTEGER_CST
&& TREE_CODE (type) == INTEGER_TYPE
- && TREE_UNSIGNED (type)
+ && TYPE_UNSIGNED (type)
&& skip_evaluation == 0
&& !int_fits_type_p (operand, type))
{
if (!int_fits_type_p (operand, c_common_signed_type (type)))
/* This detects cases like converting -129 or 256 to unsigned char. */
- warning ("large integer implicitly truncated to unsigned type");
- else if (warn_conversion)
- warning ("negative integer implicitly converted to unsigned type");
+ warning (OPT_Woverflow,
+ "large integer implicitly truncated to unsigned type");
+ else
+ warning (OPT_Wconversion,
+ "negative integer implicitly converted to unsigned type");
}
}
+/* Print a warning about casts that might indicate violation
+ of strict aliasing rules if -Wstrict-aliasing is used and
+ strict aliasing mode is in effect. OTYPE is the original
+ TREE_TYPE of EXPR, and TYPE the type we're casting to. */
+
+void
+strict_aliasing_warning (tree otype, tree type, tree expr)
+{
+ if (flag_strict_aliasing && warn_strict_aliasing
+ && POINTER_TYPE_P (type) && POINTER_TYPE_P (otype)
+ && TREE_CODE (expr) == ADDR_EXPR
+ && (DECL_P (TREE_OPERAND (expr, 0))
+ || handled_component_p (TREE_OPERAND (expr, 0)))
+ && !VOID_TYPE_P (TREE_TYPE (type)))
+ {
+ /* Casting the address of an object to non void pointer. Warn
+ if the cast breaks type based aliasing. */
+ if (!COMPLETE_TYPE_P (TREE_TYPE (type)))
+ warning (OPT_Wstrict_aliasing, "type-punning to incomplete type "
+ "might break strict-aliasing rules");
+ else
+ {
+ HOST_WIDE_INT set1 = get_alias_set (TREE_TYPE (TREE_OPERAND (expr, 0)));
+ HOST_WIDE_INT set2 = get_alias_set (TREE_TYPE (type));
+
+ if (!alias_sets_conflict_p (set1, set2))
+ warning (OPT_Wstrict_aliasing, "dereferencing type-punned "
+ "pointer will break strict-aliasing rules");
+ else if (warn_strict_aliasing > 1
+ && !alias_sets_might_conflict_p (set1, set2))
+ warning (OPT_Wstrict_aliasing, "dereferencing type-punned "
+ "pointer might break strict-aliasing rules");
+ }
+ }
+}
+
+
+/* Print a warning about if (); or if () .. else; constructs
+ via the special empty statement node that we create. INNER_THEN
+ and INNER_ELSE are the statement lists of the if and the else
+ block. */
+
+void
+empty_body_warning (tree inner_then, tree inner_else)
+{
+ if (extra_warnings)
+ {
+ if (TREE_CODE (inner_then) == STATEMENT_LIST
+ && STATEMENT_LIST_TAIL (inner_then))
+ inner_then = STATEMENT_LIST_TAIL (inner_then)->stmt;
+
+ if (inner_else && TREE_CODE (inner_else) == STATEMENT_LIST
+ && STATEMENT_LIST_TAIL (inner_else))
+ inner_else = STATEMENT_LIST_TAIL (inner_else)->stmt;
+
+ if (IS_EMPTY_STMT (inner_then) && !inner_else)
+ warning (OPT_Wextra, "%Hempty body in an if-statement",
+ EXPR_LOCUS (inner_then));
+
+ if (inner_else && IS_EMPTY_STMT (inner_else))
+ warning (OPT_Wextra, "%Hempty body in an else-statement",
+ EXPR_LOCUS (inner_else));
+ }
+}
+
+
/* Nonzero if constant C has a value that is permissible
for type TYPE (an INTEGER_TYPE). */
@@ -1288,7 +1064,9 @@ vector_types_convertible_p (tree t1, tree t2)
{
return targetm.vector_opaque_p (t1)
|| targetm.vector_opaque_p (t2)
- || (tree_int_cst_equal (TYPE_SIZE (t1), TYPE_SIZE (t2))
+ || (tree_int_cst_equal (TYPE_SIZE (t1), TYPE_SIZE (t2))
+ && (TREE_CODE (TREE_TYPE (t1)) != REAL_TYPE ||
+ TYPE_PRECISION (t1) == TYPE_PRECISION (t2))
&& INTEGRAL_TYPE_P (TREE_TYPE (t1))
== INTEGRAL_TYPE_P (TREE_TYPE (t2)));
}
@@ -1309,20 +1087,22 @@ convert_and_check (tree type, tree expr)
/* Do not diagnose overflow in a constant expression merely
because a conversion overflowed. */
- TREE_CONSTANT_OVERFLOW (t) = TREE_CONSTANT_OVERFLOW (expr);
+ TREE_CONSTANT_OVERFLOW (t) = CONSTANT_CLASS_P (expr)
+ && TREE_CONSTANT_OVERFLOW (expr);
/* No warning for converting 0x80000000 to int. */
- if (!(TREE_UNSIGNED (type) < TREE_UNSIGNED (TREE_TYPE (expr))
+ if (!(TYPE_UNSIGNED (type) < TYPE_UNSIGNED (TREE_TYPE (expr))
&& TREE_CODE (TREE_TYPE (expr)) == INTEGER_TYPE
&& TYPE_PRECISION (type) == TYPE_PRECISION (TREE_TYPE (expr))))
/* If EXPR fits in the unsigned version of TYPE,
don't warn unless pedantic. */
if ((pedantic
- || TREE_UNSIGNED (type)
- || ! constant_fits_type_p (expr,
- c_common_unsigned_type (type)))
- && skip_evaluation == 0)
- warning ("overflow in implicit constant conversion");
+ || TYPE_UNSIGNED (type)
+ || !constant_fits_type_p (expr,
+ c_common_unsigned_type (type)))
+ && skip_evaluation == 0)
+ warning (OPT_Woverflow,
+ "overflow in implicit constant conversion");
}
else
unsigned_conversion_warning (t, expr);
@@ -1368,14 +1148,13 @@ static int warning_candidate_p (tree);
static void warn_for_collisions (struct tlist *);
static void warn_for_collisions_1 (tree, tree, struct tlist *, int);
static struct tlist *new_tlist (struct tlist *, tree, tree);
-static void verify_sequence_points (tree);
/* Create a new struct tlist and fill in its fields. */
static struct tlist *
new_tlist (struct tlist *next, tree t, tree writer)
{
struct tlist *l;
- l = obstack_alloc (&tlist_obstack, sizeof *l);
+ l = XOBNEW (&tlist_obstack, struct tlist);
l->next = next;
l->expr = t;
l->writer = writer;
@@ -1391,9 +1170,9 @@ add_tlist (struct tlist **to, struct tlist *add, tree exclude_writer, int copy)
while (add)
{
struct tlist *next = add->next;
- if (! copy)
+ if (!copy)
add->next = *to;
- if (! exclude_writer || add->writer != exclude_writer)
+ if (!exclude_writer || add->writer != exclude_writer)
*to = copy ? new_tlist (*to, add->expr, add->writer) : add;
add = next;
}
@@ -1423,10 +1202,10 @@ merge_tlist (struct tlist **to, struct tlist *add, int copy)
if (tmp2->expr == add->expr)
{
found = 1;
- if (! tmp2->writer)
+ if (!tmp2->writer)
tmp2->writer = add->writer;
}
- if (! found)
+ if (!found)
{
*end = copy ? add : new_tlist (NULL, add->expr, add->writer);
end = &(*end)->next;
@@ -1455,11 +1234,11 @@ warn_for_collisions_1 (tree written, tree writer, struct tlist *list,
{
if (list->expr == written
&& list->writer != writer
- && (! only_writes || list->writer))
+ && (!only_writes || list->writer)
+ && DECL_NAME (list->expr))
{
warned_ids = new_tlist (warned_ids, written, NULL_TREE);
- warning ("operation on `%s' may be undefined",
- IDENTIFIER_POINTER (DECL_NAME (list->expr)));
+ warning (0, "operation on %qE may be undefined", list->expr);
}
list = list->next;
}
@@ -1519,7 +1298,7 @@ verify_tree (tree x, struct tlist **pbefore_sp, struct tlist **pno_sp,
{
struct tlist *tmp_before, *tmp_nosp, *tmp_list2, *tmp_list3;
enum tree_code code;
- char class;
+ enum tree_code_class cl;
/* X may be NULL if it is the operand of an empty statement expression
({ }). */
@@ -1528,7 +1307,7 @@ verify_tree (tree x, struct tlist **pbefore_sp, struct tlist **pno_sp,
restart:
code = TREE_CODE (x);
- class = TREE_CODE_CLASS (code);
+ cl = TREE_CODE_CLASS (code);
if (warning_candidate_p (x))
{
@@ -1643,9 +1422,9 @@ verify_tree (tree x, struct tlist **pbefore_sp, struct tlist **pno_sp,
if (t->expr == x)
break;
- if (! t)
+ if (!t)
{
- t = obstack_alloc (&tlist_obstack, sizeof *t);
+ t = XOBNEW (&tlist_obstack, struct tlist_cache);
t->next = save_expr_cache;
t->expr = x;
save_expr_cache = t;
@@ -1668,47 +1447,37 @@ verify_tree (tree x, struct tlist **pbefore_sp, struct tlist **pno_sp,
add_tlist (pno_sp, t->cache_after_sp, NULL_TREE, 1);
return;
}
- default:
- break;
- }
- if (class == '1')
- {
- if (first_rtl_op (code) == 0)
- return;
- x = TREE_OPERAND (x, 0);
- writer = 0;
- goto restart;
- }
-
- switch (class)
- {
- case 'r':
- case '<':
- case '2':
- case 'b':
- case 'e':
- case 's':
- case 'x':
- {
- int lp;
- int max = first_rtl_op (TREE_CODE (x));
- for (lp = 0; lp < max; lp++)
- {
- tmp_before = tmp_nosp = 0;
- verify_tree (TREE_OPERAND (x, lp), &tmp_before, &tmp_nosp, NULL_TREE);
- merge_tlist (&tmp_nosp, tmp_before, 0);
- add_tlist (pno_sp, tmp_nosp, NULL_TREE, 0);
- }
- break;
- }
+ default:
+ /* For other expressions, simply recurse on their operands.
+ Manual tail recursion for unary expressions.
+ Other non-expressions need not be processed. */
+ if (cl == tcc_unary)
+ {
+ x = TREE_OPERAND (x, 0);
+ writer = 0;
+ goto restart;
+ }
+ else if (IS_EXPR_CODE_CLASS (cl))
+ {
+ int lp;
+ int max = TREE_CODE_LENGTH (TREE_CODE (x));
+ for (lp = 0; lp < max; lp++)
+ {
+ tmp_before = tmp_nosp = 0;
+ verify_tree (TREE_OPERAND (x, lp), &tmp_before, &tmp_nosp, 0);
+ merge_tlist (&tmp_nosp, tmp_before, 0);
+ add_tlist (pno_sp, tmp_nosp, NULL_TREE, 0);
+ }
+ }
+ return;
}
}
/* Try to warn for undefined behavior in EXPR due to missing sequence
points. */
-static void
+void
verify_sequence_points (tree expr)
{
struct tlist *before_sp = 0, *after_sp = 0;
@@ -1718,45 +1487,24 @@ verify_sequence_points (tree expr)
if (tlist_firstobj == 0)
{
gcc_obstack_init (&tlist_obstack);
- tlist_firstobj = obstack_alloc (&tlist_obstack, 0);
+ tlist_firstobj = (char *) obstack_alloc (&tlist_obstack, 0);
}
verify_tree (expr, &before_sp, &after_sp, 0);
warn_for_collisions (after_sp);
obstack_free (&tlist_obstack, tlist_firstobj);
}
-
-tree
-c_expand_expr_stmt (tree expr)
-{
- /* Do default conversion if safe and possibly important,
- in case within ({...}). */
- if ((TREE_CODE (TREE_TYPE (expr)) == ARRAY_TYPE
- && (flag_isoc99 || lvalue_p (expr)))
- || TREE_CODE (TREE_TYPE (expr)) == FUNCTION_TYPE)
- expr = default_conversion (expr);
-
- 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 ("expression statement has incomplete type");
-
- last_expr_type = TREE_TYPE (expr);
- return add_stmt (build_stmt (EXPR_STMT, expr));
-}
/* Validate the expression after `case' and apply default promotions. */
-tree
+static tree
check_case_value (tree value)
{
if (value == NULL_TREE)
return value;
- /* Strip NON_LVALUE_EXPRs since we aren't using as an lvalue. */
+ /* ??? Can we ever get nops here for a valid case value? We
+ shouldn't for C. */
STRIP_TYPE_NOPS (value);
/* In C++, the following is allowed:
@@ -1771,21 +1519,89 @@ check_case_value (tree value)
value = fold (value);
}
- if (TREE_CODE (value) != INTEGER_CST
- && value != error_mark_node)
+ if (TREE_CODE (value) == INTEGER_CST)
+ /* Promote char or short to int. */
+ value = perform_integral_promotions (value);
+ else if (value != error_mark_node)
{
error ("case label does not reduce to an integer constant");
value = error_mark_node;
}
- else
- /* Promote char or short to int. */
- value = default_conversion (value);
constant_expression_warning (value);
return value;
}
+/* See if the case values LOW and HIGH are in the range of the original
+ type (i.e. before the default conversion to int) of the switch testing
+ expression.
+ TYPE is the promoted type of the testing expression, and ORIG_TYPE is
+ the type before promoting it. CASE_LOW_P is a pointer to the lower
+ bound of the case label, and CASE_HIGH_P is the upper bound or NULL
+ if the case is not a case range.
+ The caller has to make sure that we are not called with NULL for
+ CASE_LOW_P (i.e. the default case).
+ Returns true if the case label is in range of ORIG_TYPE (saturated or
+ untouched) or false if the label is out of range. */
+
+static bool
+check_case_bounds (tree type, tree orig_type,
+ tree *case_low_p, tree *case_high_p)
+{
+ tree min_value, max_value;
+ tree case_low = *case_low_p;
+ tree case_high = case_high_p ? *case_high_p : case_low;
+
+ /* If there was a problem with the original type, do nothing. */
+ if (orig_type == error_mark_node)
+ return true;
+
+ min_value = TYPE_MIN_VALUE (orig_type);
+ max_value = TYPE_MAX_VALUE (orig_type);
+
+ /* Case label is less than minimum for type. */
+ if (tree_int_cst_compare (case_low, min_value) < 0
+ && tree_int_cst_compare (case_high, min_value) < 0)
+ {
+ warning (0, "case label value is less than minimum value for type");
+ return false;
+ }
+
+ /* Case value is greater than maximum for type. */
+ if (tree_int_cst_compare (case_low, max_value) > 0
+ && tree_int_cst_compare (case_high, max_value) > 0)
+ {
+ warning (0, "case label value exceeds maximum value for type");
+ return false;
+ }
+
+ /* Saturate lower case label value to minimum. */
+ if (tree_int_cst_compare (case_high, min_value) >= 0
+ && tree_int_cst_compare (case_low, min_value) < 0)
+ {
+ warning (0, "lower value in case label range"
+ " less than minimum value for type");
+ case_low = min_value;
+ }
+
+ /* Saturate upper case label value to maximum. */
+ if (tree_int_cst_compare (case_low, max_value) <= 0
+ && tree_int_cst_compare (case_high, max_value) > 0)
+ {
+ warning (0, "upper value in case label range"
+ " exceeds maximum value for type");
+ case_high = max_value;
+ }
+
+ if (*case_low_p != case_low)
+ *case_low_p = convert (type, case_low);
+ if (case_high_p && *case_high_p != case_high)
+ *case_high_p = convert (type, case_high);
+
+ return true;
+}
+
/* Return an integer type with BITS bits of precision,
that is unsigned if UNSIGNEDP is nonzero, otherwise signed. */
@@ -1857,7 +1673,7 @@ c_common_type_for_mode (enum machine_mode mode, int unsignedp)
if (mode == TYPE_MODE (widest_integer_literal_type_node))
return unsignedp ? widest_unsigned_literal_type_node
- : widest_integer_literal_type_node;
+ : widest_integer_literal_type_node;
if (mode == QImode)
return unsignedp ? unsigned_intQI_type_node : intQI_type_node;
@@ -1887,46 +1703,51 @@ c_common_type_for_mode (enum machine_mode mode, int unsignedp)
if (mode == TYPE_MODE (void_type_node))
return void_type_node;
-
+
if (mode == TYPE_MODE (build_pointer_type (char_type_node)))
- return unsignedp ? make_unsigned_type (mode) : make_signed_type (mode);
+ return (unsignedp
+ ? make_unsigned_type (GET_MODE_PRECISION (mode))
+ : make_signed_type (GET_MODE_PRECISION (mode)));
if (mode == TYPE_MODE (build_pointer_type (integer_type_node)))
- return unsignedp ? make_unsigned_type (mode) : make_signed_type (mode);
-
- switch (mode)
- {
- case V16QImode:
- return unsignedp ? unsigned_V16QI_type_node : V16QI_type_node;
- case V8HImode:
- return unsignedp ? unsigned_V8HI_type_node : V8HI_type_node;
- case V4SImode:
- return unsignedp ? unsigned_V4SI_type_node : V4SI_type_node;
- case V2DImode:
- return unsignedp ? unsigned_V2DI_type_node : V2DI_type_node;
- case V2SImode:
- return unsignedp ? unsigned_V2SI_type_node : V2SI_type_node;
- case V2HImode:
- return unsignedp ? unsigned_V2HI_type_node : V2HI_type_node;
- case V4HImode:
- return unsignedp ? unsigned_V4HI_type_node : V4HI_type_node;
- case V8QImode:
- return unsignedp ? unsigned_V8QI_type_node : V8QI_type_node;
- case V1DImode:
- return unsignedp ? unsigned_V1DI_type_node : V1DI_type_node;
- case V16SFmode:
- return V16SF_type_node;
- case V4SFmode:
- return V4SF_type_node;
- case V2SFmode:
- return V2SF_type_node;
- case V2DFmode:
- return V2DF_type_node;
- case V4DFmode:
- return V4DF_type_node;
- default:
- break;
+ return (unsignedp
+ ? make_unsigned_type (GET_MODE_PRECISION (mode))
+ : make_signed_type (GET_MODE_PRECISION (mode)));
+
+ if (COMPLEX_MODE_P (mode))
+ {
+ enum machine_mode inner_mode;
+ tree inner_type;
+
+ if (mode == TYPE_MODE (complex_float_type_node))
+ return complex_float_type_node;
+ if (mode == TYPE_MODE (complex_double_type_node))
+ return complex_double_type_node;
+ if (mode == TYPE_MODE (complex_long_double_type_node))
+ return complex_long_double_type_node;
+
+ if (mode == TYPE_MODE (complex_integer_type_node) && !unsignedp)
+ return complex_integer_type_node;
+
+ inner_mode = GET_MODE_INNER (mode);
+ inner_type = c_common_type_for_mode (inner_mode, unsignedp);
+ if (inner_type != NULL_TREE)
+ return build_complex_type (inner_type);
}
+ else if (VECTOR_MODE_P (mode))
+ {
+ enum machine_mode inner_mode = GET_MODE_INNER (mode);
+ tree inner_type = c_common_type_for_mode (inner_mode, unsignedp);
+ if (inner_type != NULL_TREE)
+ return build_vector_type_for_mode (inner_type, mode);
+ }
+
+ if (mode == TYPE_MODE (dfloat32_type_node))
+ return dfloat32_type_node;
+ if (mode == TYPE_MODE (dfloat64_type_node))
+ return dfloat64_type_node;
+ if (mode == TYPE_MODE (dfloat128_type_node))
+ return dfloat128_type_node;
for (t = registered_builtin_types; t; t = TREE_CHAIN (t))
if (TYPE_MODE (TREE_VALUE (t)) == mode)
@@ -2008,44 +1829,80 @@ c_common_signed_type (tree type)
tree
c_common_signed_or_unsigned_type (int unsignedp, tree type)
{
- if (! INTEGRAL_TYPE_P (type)
- || TREE_UNSIGNED (type) == unsignedp)
+ if (!INTEGRAL_TYPE_P (type)
+ || TYPE_UNSIGNED (type) == unsignedp)
return type;
- /* Must check the mode of the types, not the precision. Enumeral types
- in C++ have precision set to match their range, but may use a wider
- mode to match an ABI. If we change modes, we may wind up with bad
- conversions. */
-
- if (TYPE_MODE (type) == TYPE_MODE (signed_char_type_node))
+ /* For ENUMERAL_TYPEs in C++, must check the mode of the types, not
+ the precision; they have precision set to match their range, but
+ may use a wider mode to match an ABI. If we change modes, we may
+ wind up with bad conversions. For INTEGER_TYPEs in C, must check
+ the precision as well, so as to yield correct results for
+ bit-field types. C++ does not have these separate bit-field
+ types, and producing a signed or unsigned variant of an
+ ENUMERAL_TYPE may cause other problems as well. */
+
+#define TYPE_OK(node) \
+ (TYPE_MODE (type) == TYPE_MODE (node) \
+ && (c_dialect_cxx () || TYPE_PRECISION (type) == TYPE_PRECISION (node)))
+ if (TYPE_OK (signed_char_type_node))
return unsignedp ? unsigned_char_type_node : signed_char_type_node;
- if (TYPE_MODE (type) == TYPE_MODE (integer_type_node))
+ if (TYPE_OK (integer_type_node))
return unsignedp ? unsigned_type_node : integer_type_node;
- if (TYPE_MODE (type) == TYPE_MODE (short_integer_type_node))
+ if (TYPE_OK (short_integer_type_node))
return unsignedp ? short_unsigned_type_node : short_integer_type_node;
- if (TYPE_MODE (type) == TYPE_MODE (long_integer_type_node))
+ if (TYPE_OK (long_integer_type_node))
return unsignedp ? long_unsigned_type_node : long_integer_type_node;
- if (TYPE_MODE (type) == TYPE_MODE (long_long_integer_type_node))
+ if (TYPE_OK (long_long_integer_type_node))
return (unsignedp ? long_long_unsigned_type_node
: long_long_integer_type_node);
- if (TYPE_MODE (type) == TYPE_MODE (widest_integer_literal_type_node))
+ if (TYPE_OK (widest_integer_literal_type_node))
return (unsignedp ? widest_unsigned_literal_type_node
: widest_integer_literal_type_node);
#if HOST_BITS_PER_WIDE_INT >= 64
- if (TYPE_MODE (type) == TYPE_MODE (intTI_type_node))
+ if (TYPE_OK (intTI_type_node))
return unsignedp ? unsigned_intTI_type_node : intTI_type_node;
#endif
- if (TYPE_MODE (type) == TYPE_MODE (intDI_type_node))
+ if (TYPE_OK (intDI_type_node))
return unsignedp ? unsigned_intDI_type_node : intDI_type_node;
- if (TYPE_MODE (type) == TYPE_MODE (intSI_type_node))
+ if (TYPE_OK (intSI_type_node))
return unsignedp ? unsigned_intSI_type_node : intSI_type_node;
- if (TYPE_MODE (type) == TYPE_MODE (intHI_type_node))
+ if (TYPE_OK (intHI_type_node))
return unsignedp ? unsigned_intHI_type_node : intHI_type_node;
- if (TYPE_MODE (type) == TYPE_MODE (intQI_type_node))
+ if (TYPE_OK (intQI_type_node))
return unsignedp ? unsigned_intQI_type_node : intQI_type_node;
+#undef TYPE_OK
- return type;
+ if (c_dialect_cxx ())
+ return type;
+ else
+ return build_nonstandard_integer_type (TYPE_PRECISION (type), unsignedp);
+}
+
+/* Build a bit-field integer type for the given WIDTH and UNSIGNEDP. */
+
+tree
+c_build_bitfield_integer_type (unsigned HOST_WIDE_INT width, int unsignedp)
+{
+ /* Extended integer types of the same width as a standard type have
+ lesser rank, so those of the same width as int promote to int or
+ unsigned int and are valid for printf formats expecting int or
+ unsigned int. To avoid such special cases, avoid creating
+ extended integer types for bit-fields if a standard integer type
+ is available. */
+ if (width == TYPE_PRECISION (integer_type_node))
+ return unsignedp ? unsigned_type_node : integer_type_node;
+ if (width == TYPE_PRECISION (signed_char_type_node))
+ return unsignedp ? unsigned_char_type_node : signed_char_type_node;
+ if (width == TYPE_PRECISION (short_integer_type_node))
+ return unsignedp ? short_unsigned_type_node : short_integer_type_node;
+ if (width == TYPE_PRECISION (long_integer_type_node))
+ return unsignedp ? long_unsigned_type_node : long_integer_type_node;
+ if (width == TYPE_PRECISION (long_long_integer_type_node))
+ return (unsignedp ? long_long_unsigned_type_node
+ : long_long_integer_type_node);
+ return build_nonstandard_integer_type (width, unsignedp);
}
/* The C version of the register_builtin_type langhook. */
@@ -2079,7 +1936,7 @@ min_precision (tree value, int unsignedp)
a bit-wise negation, so use that operation instead. */
if (tree_int_cst_sgn (value) < 0)
- value = fold (build1 (BIT_NOT_EXPR, TREE_TYPE (value), value));
+ value = fold_build1 (BIT_NOT_EXPR, TREE_TYPE (value), value);
/* Return the number of bits needed, taking into account the fact
that we need one more bit for a signed than unsigned type. */
@@ -2089,12 +1946,11 @@ min_precision (tree value, int unsignedp)
else
log = tree_floor_log2 (value);
- return log + 1 + ! unsignedp;
+ return log + 1 + !unsignedp;
}
/* Print an error message for invalid operands to arith operation
- CODE. NOP_EXPR is used as a special case (see
- c_common_truthvalue_conversion). */
+ CODE. */
void
binary_op_error (enum tree_code code)
@@ -2103,10 +1959,6 @@ binary_op_error (enum tree_code code)
switch (code)
{
- case NOP_EXPR:
- error ("invalid truth-value expression");
- return;
-
case PLUS_EXPR:
opname = "+"; break;
case MINUS_EXPR:
@@ -2149,11 +2001,8 @@ binary_op_error (enum tree_code code)
opname = "||"; break;
case BIT_XOR_EXPR:
opname = "^"; break;
- case LROTATE_EXPR:
- case RROTATE_EXPR:
- opname = "rotate"; break;
default:
- opname = "unknown"; break;
+ gcc_unreachable ();
}
error ("invalid operands to binary %s", opname);
}
@@ -2194,9 +2043,9 @@ shorten_compare (tree *op0_ptr, tree *op1_ptr, tree *restype_ptr,
but it *requires* conversion to FINAL_TYPE. */
if (op0 == primop0 && TREE_TYPE (op0) != *restype_ptr)
- unsignedp0 = TREE_UNSIGNED (TREE_TYPE (op0));
+ unsignedp0 = TYPE_UNSIGNED (TREE_TYPE (op0));
if (op1 == primop1 && TREE_TYPE (op1) != *restype_ptr)
- unsignedp1 = TREE_UNSIGNED (TREE_TYPE (op1));
+ unsignedp1 = TYPE_UNSIGNED (TREE_TYPE (op1));
/* If one of the operands must be floated, we cannot optimize. */
real1 = TREE_CODE (TREE_TYPE (primop0)) == REAL_TYPE;
@@ -2207,7 +2056,7 @@ shorten_compare (tree *op0_ptr, tree *op1_ptr, tree *restype_ptr,
the second arg is 0. */
if (TREE_CONSTANT (primop0)
- && ! integer_zerop (primop1) && ! real_zerop (primop1))
+ && !integer_zerop (primop1) && !real_zerop (primop1))
{
tree tem = primop0;
int temi = unsignedp0;
@@ -2268,20 +2117,12 @@ shorten_compare (tree *op0_ptr, tree *op1_ptr, tree *restype_ptr,
int min_gt, max_gt, min_lt, max_lt;
tree maxval, minval;
/* 1 if comparison is nominally unsigned. */
- int unsignedp = TREE_UNSIGNED (*restype_ptr);
+ int unsignedp = TYPE_UNSIGNED (*restype_ptr);
tree val;
type = c_common_signed_or_unsigned_type (unsignedp0,
TREE_TYPE (primop0));
- /* In C, if TYPE is an enumeration, then we need to get its
- min/max values from it's underlying integral type, not the
- enumerated type itself. In C++, TYPE_MAX_VALUE and
- TYPE_MIN_VALUE have already been set correctly on the
- enumeration type. */
- if (!c_dialect_cxx() && TREE_CODE (type) == ENUMERAL_TYPE)
- type = c_common_type_for_size (TYPE_PRECISION (type), unsignedp0);
-
maxval = TYPE_MAX_VALUE (type);
minval = TYPE_MIN_VALUE (type);
@@ -2289,7 +2130,16 @@ shorten_compare (tree *op0_ptr, tree *op1_ptr, tree *restype_ptr,
*restype_ptr = c_common_signed_type (*restype_ptr);
if (TREE_TYPE (primop1) != *restype_ptr)
- primop1 = convert (*restype_ptr, primop1);
+ {
+ /* Convert primop1 to target type, but do not introduce
+ additional overflow. We know primop1 is an int_cst. */
+ tree tmp = build_int_cst_wide (*restype_ptr,
+ TREE_INT_CST_LOW (primop1),
+ TREE_INT_CST_HIGH (primop1));
+
+ primop1 = force_fit_type (tmp, 0, TREE_OVERFLOW (primop1),
+ TREE_CONSTANT_OVERFLOW (primop1));
+ }
if (type != *restype_ptr)
{
minval = convert (*restype_ptr, minval);
@@ -2389,16 +2239,16 @@ shorten_compare (tree *op0_ptr, tree *op1_ptr, tree *restype_ptr,
if (TREE_CODE (primop0) != INTEGER_CST)
{
if (val == truthvalue_false_node)
- warning ("comparison is always false due to limited range of data type");
+ warning (0, "comparison is always false due to limited range of data type");
if (val == truthvalue_true_node)
- warning ("comparison is always true due to limited range of data type");
+ warning (0, "comparison is always true due to limited range of data type");
}
if (val != 0)
{
/* Don't forget to evaluate PRIMOP0 if it has side effects. */
if (TREE_SIDE_EFFECTS (primop0))
- return build (COMPOUND_EXPR, TREE_TYPE (val), primop0, val);
+ return build2 (COMPOUND_EXPR, TREE_TYPE (val), primop0, val);
return val;
}
@@ -2406,6 +2256,14 @@ shorten_compare (tree *op0_ptr, tree *op1_ptr, tree *restype_ptr,
in the type of the operand that is not constant.
TYPE is already properly set. */
}
+
+ /* If either arg is decimal float and the other is float, find the
+ proper common type to use for comparison. */
+ else if (real1 && real2
+ && (DECIMAL_FLOAT_MODE_P (TYPE_MODE (TREE_TYPE (primop0)))
+ || DECIMAL_FLOAT_MODE_P (TYPE_MODE (TREE_TYPE (primop1)))))
+ type = common_type (TREE_TYPE (primop0), TREE_TYPE (primop1));
+
else if (real1 && real2
&& (TYPE_PRECISION (TREE_TYPE (primop0))
== TYPE_PRECISION (TREE_TYPE (primop1))))
@@ -2425,7 +2283,7 @@ shorten_compare (tree *op0_ptr, tree *op1_ptr, tree *restype_ptr,
{
type = common_type (TREE_TYPE (primop0), TREE_TYPE (primop1));
type = c_common_signed_or_unsigned_type (unsignedp0
- || TREE_UNSIGNED (*restype_ptr),
+ || TYPE_UNSIGNED (*restype_ptr),
type);
/* Make sure shorter operand is extended the right way
to match the longer operand. */
@@ -2447,7 +2305,7 @@ shorten_compare (tree *op0_ptr, tree *op1_ptr, tree *restype_ptr,
primop1 = op1;
if (!real1 && !real2 && integer_zerop (primop1)
- && TREE_UNSIGNED (*restype_ptr))
+ && TYPE_UNSIGNED (*restype_ptr))
{
tree value = 0;
switch (code)
@@ -2458,19 +2316,19 @@ shorten_compare (tree *op0_ptr, tree *op1_ptr, tree *restype_ptr,
>= 0, the signedness of the comparison isn't an issue,
so suppress the warning. */
if (extra_warnings && !in_system_header
- && ! (TREE_CODE (primop0) == INTEGER_CST
- && ! TREE_OVERFLOW (convert (c_common_signed_type (type),
- primop0))))
- warning ("comparison of unsigned expression >= 0 is always true");
+ && !(TREE_CODE (primop0) == INTEGER_CST
+ && !TREE_OVERFLOW (convert (c_common_signed_type (type),
+ primop0))))
+ warning (0, "comparison of unsigned expression >= 0 is always true");
value = truthvalue_true_node;
break;
case LT_EXPR:
if (extra_warnings && !in_system_header
- && ! (TREE_CODE (primop0) == INTEGER_CST
- && ! TREE_OVERFLOW (convert (c_common_signed_type (type),
- primop0))))
- warning ("comparison of unsigned expression < 0 is always false");
+ && !(TREE_CODE (primop0) == INTEGER_CST
+ && !TREE_OVERFLOW (convert (c_common_signed_type (type),
+ primop0))))
+ warning (0, "comparison of unsigned expression < 0 is always false");
value = truthvalue_false_node;
break;
@@ -2482,8 +2340,8 @@ shorten_compare (tree *op0_ptr, tree *op1_ptr, tree *restype_ptr,
{
/* Don't forget to evaluate PRIMOP0 if it has side effects. */
if (TREE_SIDE_EFFECTS (primop0))
- return build (COMPOUND_EXPR, TREE_TYPE (value),
- primop0, value);
+ return build2 (COMPOUND_EXPR, TREE_TYPE (value),
+ primop0, value);
return value;
}
}
@@ -2503,10 +2361,7 @@ shorten_compare (tree *op0_ptr, tree *op1_ptr, tree *restype_ptr,
tree
pointer_int_sum (enum tree_code resultcode, tree ptrop, tree intop)
{
- tree size_exp;
-
- tree result;
- tree folded;
+ tree size_exp, ret;
/* The result is a pointer of the same type that is being added. */
@@ -2515,7 +2370,7 @@ pointer_int_sum (enum tree_code resultcode, tree ptrop, tree intop)
if (TREE_CODE (TREE_TYPE (result_type)) == VOID_TYPE)
{
if (pedantic || warn_pointer_arith)
- pedwarn ("pointer of type `void *' used in arithmetic");
+ pedwarn ("pointer of type %<void *%> used in arithmetic");
size_exp = integer_one_node;
}
else if (TREE_CODE (TREE_TYPE (result_type)) == FUNCTION_TYPE)
@@ -2533,13 +2388,19 @@ pointer_int_sum (enum tree_code resultcode, tree ptrop, tree intop)
else
size_exp = size_in_bytes (TREE_TYPE (result_type));
+ /* We are manipulating pointer values, so we don't need to warn
+ about relying on undefined signed overflow. We disable the
+ warning here because we use integer types so fold won't know that
+ they are really pointers. */
+ fold_defer_overflow_warnings ();
+
/* If what we are about to multiply by the size of the elements
contains a constant term, apply distributive law
and multiply that constant term separately.
This helps produce common subexpressions. */
if ((TREE_CODE (intop) == PLUS_EXPR || TREE_CODE (intop) == MINUS_EXPR)
- && ! TREE_CONSTANT (intop)
+ && !TREE_CONSTANT (intop)
&& TREE_CONSTANT (TREE_OPERAND (intop, 1))
&& TREE_CONSTANT (size_exp)
/* If the constant comes from pointer subtraction,
@@ -2548,7 +2409,7 @@ pointer_int_sum (enum tree_code resultcode, tree ptrop, tree intop)
/* If the constant is unsigned, and smaller than the pointer size,
then we must skip this optimization. This is because it could cause
an overflow error if the constant is negative but INTOP is not. */
- && (! TREE_UNSIGNED (TREE_TYPE (intop))
+ && (!TYPE_UNSIGNED (TREE_TYPE (intop))
|| (TYPE_PRECISION (TREE_TYPE (intop))
== TYPE_PRECISION (TREE_TYPE (ptrop)))))
{
@@ -2568,9 +2429,9 @@ pointer_int_sum (enum tree_code resultcode, tree ptrop, tree intop)
so the multiply won't overflow spuriously. */
if (TYPE_PRECISION (TREE_TYPE (intop)) != TYPE_PRECISION (sizetype)
- || TREE_UNSIGNED (TREE_TYPE (intop)) != TREE_UNSIGNED (sizetype))
+ || TYPE_UNSIGNED (TREE_TYPE (intop)) != TYPE_UNSIGNED (sizetype))
intop = convert (c_common_type_for_size (TYPE_PRECISION (sizetype),
- TREE_UNSIGNED (sizetype)), intop);
+ TYPE_UNSIGNED (sizetype)), intop);
/* Replace the integer argument with a suitable product by the object size.
Do this multiplication as signed, then convert to the appropriate
@@ -2581,17 +2442,17 @@ pointer_int_sum (enum tree_code resultcode, tree ptrop, tree intop)
convert (TREE_TYPE (intop), size_exp), 1));
/* Create the sum or difference. */
+ ret = fold_build2 (resultcode, result_type, ptrop, intop);
- result = build (resultcode, result_type, ptrop, intop);
+ fold_undefer_and_ignore_overflow_warnings ();
- folded = fold (result);
- if (folded == result)
- TREE_CONSTANT (folded) = TREE_CONSTANT (ptrop) & TREE_CONSTANT (intop);
- return folded;
+ return ret;
}
/* Prepare expr to be an argument of a TRUTH_NOT_EXPR,
- or validate its data type for an `if' or `while' statement or ?..: exp.
+ or for an `if' or `while' statement or ?..: exp. It should already
+ have been validated to be of suitable type; otherwise, a bad
+ diagnostic may result.
This preparation consists of taking the ordinary
representation of an expression expr and producing a valid tree
@@ -2604,77 +2465,77 @@ pointer_int_sum (enum tree_code resultcode, tree ptrop, tree intop)
tree
c_common_truthvalue_conversion (tree expr)
{
- if (TREE_CODE (expr) == ERROR_MARK)
- return expr;
-
- if (TREE_CODE (expr) == FUNCTION_DECL)
- expr = build_unary_op (ADDR_EXPR, expr, 0);
-
-#if 0 /* This appears to be wrong for C++. */
- /* These really should return error_mark_node after 2.4 is stable.
- But not all callers handle ERROR_MARK properly. */
- switch (TREE_CODE (TREE_TYPE (expr)))
- {
- case RECORD_TYPE:
- error ("struct type value used where scalar is required");
- return truthvalue_false_node;
-
- case UNION_TYPE:
- error ("union type value used where scalar is required");
- return truthvalue_false_node;
-
- case ARRAY_TYPE:
- error ("array type value used where scalar is required");
- return truthvalue_false_node;
-
- default:
- break;
- }
-#endif /* 0 */
-
switch (TREE_CODE (expr))
{
- case EQ_EXPR:
- case NE_EXPR: case LE_EXPR: case GE_EXPR: case LT_EXPR: case GT_EXPR:
+ case EQ_EXPR: case NE_EXPR: case UNEQ_EXPR: case LTGT_EXPR:
+ case LE_EXPR: case GE_EXPR: case LT_EXPR: case GT_EXPR:
+ case UNLE_EXPR: case UNGE_EXPR: case UNLT_EXPR: case UNGT_EXPR:
+ case ORDERED_EXPR: case UNORDERED_EXPR:
+ if (TREE_TYPE (expr) == truthvalue_type_node)
+ return expr;
+ return build2 (TREE_CODE (expr), truthvalue_type_node,
+ TREE_OPERAND (expr, 0), TREE_OPERAND (expr, 1));
+
case TRUTH_ANDIF_EXPR:
case TRUTH_ORIF_EXPR:
case TRUTH_AND_EXPR:
case TRUTH_OR_EXPR:
case TRUTH_XOR_EXPR:
+ if (TREE_TYPE (expr) == truthvalue_type_node)
+ return expr;
+ return build2 (TREE_CODE (expr), truthvalue_type_node,
+ c_common_truthvalue_conversion (TREE_OPERAND (expr, 0)),
+ c_common_truthvalue_conversion (TREE_OPERAND (expr, 1)));
+
case TRUTH_NOT_EXPR:
- TREE_TYPE (expr) = truthvalue_type_node;
- return expr;
+ if (TREE_TYPE (expr) == truthvalue_type_node)
+ return expr;
+ return build1 (TREE_CODE (expr), truthvalue_type_node,
+ c_common_truthvalue_conversion (TREE_OPERAND (expr, 0)));
case ERROR_MARK:
return expr;
case INTEGER_CST:
- return integer_zerop (expr) ? truthvalue_false_node : truthvalue_true_node;
+ /* Avoid integer_zerop to ignore TREE_CONSTANT_OVERFLOW. */
+ return (TREE_INT_CST_LOW (expr) != 0 || TREE_INT_CST_HIGH (expr) != 0)
+ ? truthvalue_true_node
+ : truthvalue_false_node;
case REAL_CST:
- return real_zerop (expr) ? truthvalue_false_node : truthvalue_true_node;
+ return real_compare (NE_EXPR, &TREE_REAL_CST (expr), &dconst0)
+ ? truthvalue_true_node
+ : truthvalue_false_node;
+
+ case FUNCTION_DECL:
+ expr = build_unary_op (ADDR_EXPR, expr, 0);
+ /* Fall through. */
case ADDR_EXPR:
{
- if (TREE_CODE (TREE_OPERAND (expr, 0)) == FUNCTION_DECL
- && ! DECL_WEAK (TREE_OPERAND (expr, 0)))
+ tree inner = TREE_OPERAND (expr, 0);
+ if (DECL_P (inner)
+ && (TREE_CODE (inner) == PARM_DECL
+ || TREE_CODE (inner) == LABEL_DECL
+ || !DECL_WEAK (inner)))
{
- /* Common Ada/Pascal programmer's mistake. We always warn
+ /* Common Ada/Pascal programmer's mistake. We always warn
about this since it is so bad. */
- warning ("the address of `%D', will always evaluate as `true'",
- TREE_OPERAND (expr, 0));
+ warning (OPT_Waddress,
+ "the address of %qD will always evaluate as %<true%>",
+ inner);
return truthvalue_true_node;
}
/* If we are taking the address of an external decl, it might be
zero if it is weak, so we cannot optimize. */
- if (DECL_P (TREE_OPERAND (expr, 0))
- && DECL_EXTERNAL (TREE_OPERAND (expr, 0)))
+ if (DECL_P (inner)
+ && DECL_EXTERNAL (inner))
break;
- if (TREE_SIDE_EFFECTS (TREE_OPERAND (expr, 0)))
- return build (COMPOUND_EXPR, truthvalue_type_node,
- TREE_OPERAND (expr, 0), truthvalue_true_node);
+ if (TREE_SIDE_EFFECTS (inner))
+ return build2 (COMPOUND_EXPR, truthvalue_type_node,
+ inner, truthvalue_true_node);
else
return truthvalue_true_node;
}
@@ -2697,65 +2558,36 @@ c_common_truthvalue_conversion (tree expr)
/* These don't change whether an object is zero or nonzero, but
we can't ignore them if their second arg has side-effects. */
if (TREE_SIDE_EFFECTS (TREE_OPERAND (expr, 1)))
- return build (COMPOUND_EXPR, truthvalue_type_node, TREE_OPERAND (expr, 1),
- c_common_truthvalue_conversion (TREE_OPERAND (expr, 0)));
+ return build2 (COMPOUND_EXPR, truthvalue_type_node,
+ TREE_OPERAND (expr, 1),
+ c_common_truthvalue_conversion (TREE_OPERAND (expr, 0)));
else
return c_common_truthvalue_conversion (TREE_OPERAND (expr, 0));
case COND_EXPR:
/* Distribute the conversion into the arms of a COND_EXPR. */
- return fold (build (COND_EXPR, truthvalue_type_node, TREE_OPERAND (expr, 0),
+ return fold_build3 (COND_EXPR, truthvalue_type_node,
+ TREE_OPERAND (expr, 0),
c_common_truthvalue_conversion (TREE_OPERAND (expr, 1)),
- c_common_truthvalue_conversion (TREE_OPERAND (expr, 2))));
+ c_common_truthvalue_conversion (TREE_OPERAND (expr, 2)));
case CONVERT_EXPR:
+ case NOP_EXPR:
/* Don't cancel the effect of a CONVERT_EXPR from a REFERENCE_TYPE,
since that affects how `default_conversion' will behave. */
if (TREE_CODE (TREE_TYPE (expr)) == REFERENCE_TYPE
|| TREE_CODE (TREE_TYPE (TREE_OPERAND (expr, 0))) == REFERENCE_TYPE)
break;
- /* Fall through.... */
- case NOP_EXPR:
/* If this is widening the argument, we can ignore it. */
if (TYPE_PRECISION (TREE_TYPE (expr))
>= TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (expr, 0))))
return c_common_truthvalue_conversion (TREE_OPERAND (expr, 0));
break;
- case MINUS_EXPR:
- /* Perhaps reduce (x - y) != 0 to (x != y). The expressions
- aren't guaranteed to the be same for modes that can represent
- infinity, since if x and y are both +infinity, or both
- -infinity, then x - y is not a number.
-
- Note that this transformation is safe when x or y is NaN.
- (x - y) is then NaN, and both (x - y) != 0 and x != y will
- be false. */
- if (HONOR_INFINITIES (TYPE_MODE (TREE_TYPE (TREE_OPERAND (expr, 0)))))
- break;
- /* Fall through.... */
- case BIT_XOR_EXPR:
- /* This and MINUS_EXPR can be changed into a comparison of the
- two objects. */
- if (TREE_TYPE (TREE_OPERAND (expr, 0))
- == TREE_TYPE (TREE_OPERAND (expr, 1)))
- return build_binary_op (NE_EXPR, TREE_OPERAND (expr, 0),
- TREE_OPERAND (expr, 1), 1);
- return build_binary_op (NE_EXPR, TREE_OPERAND (expr, 0),
- fold (build1 (NOP_EXPR,
- TREE_TYPE (TREE_OPERAND (expr, 0)),
- TREE_OPERAND (expr, 1))), 1);
-
- case BIT_AND_EXPR:
- if (integer_onep (TREE_OPERAND (expr, 1))
- && TREE_TYPE (expr) != truthvalue_type_node)
- /* Using convert here would cause infinite recursion. */
- return build1 (NOP_EXPR, truthvalue_type_node, expr);
- break;
-
case MODIFY_EXPR:
- if (warn_parentheses && C_EXP_ORIGINAL_CODE (expr) == MODIFY_EXPR)
- warning ("suggest parentheses around assignment used as truth value");
+ if (!TREE_NO_WARNING (expr))
+ warning (OPT_Wparentheses,
+ "suggest parentheses around assignment used as truth value");
break;
default:
@@ -2776,9 +2608,12 @@ c_common_truthvalue_conversion (tree expr)
return build_binary_op (NE_EXPR, expr, integer_zero_node, 1);
}
-static tree builtin_function_2 (const char *, const char *, tree, tree,
- int, enum built_in_class, int, int,
- tree);
+static void def_builtin_1 (enum built_in_function fncode,
+ const char *name,
+ enum built_in_class fnclass,
+ tree fntype, tree libtype,
+ bool both_p, bool fallback_p, bool nonansi_p,
+ tree fnattrs, bool implicit_p);
/* Make a variant type in the proper way for C/C++, propagating qualifiers
down to the element type of an array. */
@@ -2788,11 +2623,30 @@ c_build_qualified_type (tree type, int type_quals)
{
if (type == error_mark_node)
return type;
-
+
if (TREE_CODE (type) == ARRAY_TYPE)
- return build_array_type (c_build_qualified_type (TREE_TYPE (type),
- type_quals),
- TYPE_DOMAIN (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)
+ {
+ t = build_variant_type_copy (type);
+ TREE_TYPE (t) = element_type;
+ }
+ 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
@@ -2801,7 +2655,7 @@ c_build_qualified_type (tree type, int type_quals)
&& (!POINTER_TYPE_P (type)
|| !C_TYPE_OBJECT_OR_INCOMPLETE_P (TREE_TYPE (type))))
{
- error ("invalid use of `restrict'");
+ error ("invalid use of %<restrict%>");
type_quals &= ~TYPE_QUAL_RESTRICT;
}
@@ -2814,7 +2668,7 @@ void
c_apply_type_quals_to_decl (int type_quals, tree decl)
{
tree type = TREE_TYPE (decl);
-
+
if (type == error_mark_node)
return;
@@ -2841,7 +2695,7 @@ c_apply_type_quals_to_decl (int type_quals, tree decl)
if (!type
|| !POINTER_TYPE_P (type)
|| !C_TYPE_OBJECT_OR_INCOMPLETE_P (TREE_TYPE (type)))
- error ("invalid use of `restrict'");
+ error ("invalid use of %<restrict%>");
else if (flag_strict_aliasing && type == TREE_TYPE (decl))
/* Indicate we need to make a unique alias set for this pointer.
We can't do it here because it might be pointing to an
@@ -2850,6 +2704,51 @@ c_apply_type_quals_to_decl (int type_quals, tree decl)
}
}
+/* Hash function for the problem of multiple type definitions in
+ different files. This must hash all types that will compare
+ equal via comptypes to the same value. In practice it hashes
+ on some of the simple stuff and leaves the details to comptypes. */
+
+static hashval_t
+c_type_hash (const void *p)
+{
+ int i = 0;
+ int shift, size;
+ tree t = (tree) p;
+ tree t2;
+ switch (TREE_CODE (t))
+ {
+ /* For pointers, hash on pointee type plus some swizzling. */
+ case POINTER_TYPE:
+ return c_type_hash (TREE_TYPE (t)) ^ 0x3003003;
+ /* Hash on number of elements and total size. */
+ case ENUMERAL_TYPE:
+ shift = 3;
+ t2 = TYPE_VALUES (t);
+ break;
+ case RECORD_TYPE:
+ shift = 0;
+ t2 = TYPE_FIELDS (t);
+ break;
+ case QUAL_UNION_TYPE:
+ shift = 1;
+ t2 = TYPE_FIELDS (t);
+ break;
+ case UNION_TYPE:
+ shift = 2;
+ t2 = TYPE_FIELDS (t);
+ break;
+ default:
+ gcc_unreachable ();
+ }
+ for (; t2; t2 = TREE_CHAIN (t2))
+ i++;
+ size = TREE_INT_CST_LOW (TYPE_SIZE (t));
+ return ((size << 24) | (i << shift));
+}
+
+static GTY((param_is (union tree_node))) htab_t type_hash_table;
+
/* Return the typed-based alias set for T, which may be an expression
or a type. Return -1 if we don't do anything special. */
@@ -2857,6 +2756,7 @@ HOST_WIDE_INT
c_common_get_alias_set (tree t)
{
tree u;
+ PTR *slot;
/* Permit type-punning when accessing a union, provided the access
is directly through the union. For example, this code does not
@@ -2872,7 +2772,7 @@ c_common_get_alias_set (tree t)
return 0;
/* That's all the expressions we handle specially. */
- if (! TYPE_P (t))
+ if (!TYPE_P (t))
return -1;
/* The C standard guarantees that any object may be accessed via an
@@ -2889,7 +2789,7 @@ c_common_get_alias_set (tree t)
/* The C standard specifically allows aliasing between signed and
unsigned variants of the same type. We treat the signed
variant as canonical. */
- if (TREE_CODE (t) == INTEGER_TYPE && TREE_UNSIGNED (t))
+ if (TREE_CODE (t) == INTEGER_TYPE && TYPE_UNSIGNED (t))
{
tree t1 = c_common_signed_type (t);
@@ -2913,14 +2813,14 @@ c_common_get_alias_set (tree t)
technically, an `int **' and `const int **' cannot point at
the same thing.
- But, the standard is wrong. In particular, this code is
+ But, the standard is wrong. In particular, this code is
legal C++:
- int *ip;
- int **ipp = &ip;
- const int* const* cipp = &ipp;
+ int *ip;
+ int **ipp = &ip;
+ const int* const* cipp = ipp;
- And, it doesn't make sense for that to be legal unless you
+ And, it doesn't make sense for that to be legal unless you
can dereference IPP and CIPP. So, we ignore cv-qualifiers on
the pointed-to types. This issue has been reported to the
C++ committee. */
@@ -2929,6 +2829,66 @@ c_common_get_alias_set (tree t)
return get_alias_set (t1);
}
+ /* Handle the case of multiple type nodes referring to "the same" type,
+ which occurs with IMA. These share an alias set. FIXME: Currently only
+ C90 is handled. (In C99 type compatibility is not transitive, which
+ complicates things mightily. The alias set splay trees can theoretically
+ represent this, but insertion is tricky when you consider all the
+ different orders things might arrive in.) */
+
+ if (c_language != clk_c || flag_isoc99)
+ return -1;
+
+ /* Save time if there's only one input file. */
+ if (num_in_fnames == 1)
+ return -1;
+
+ /* Pointers need special handling if they point to any type that
+ needs special handling (below). */
+ if (TREE_CODE (t) == POINTER_TYPE)
+ {
+ tree t2;
+ /* Find bottom type under any nested POINTERs. */
+ for (t2 = TREE_TYPE (t);
+ TREE_CODE (t2) == POINTER_TYPE;
+ t2 = TREE_TYPE (t2))
+ ;
+ if (TREE_CODE (t2) != RECORD_TYPE
+ && TREE_CODE (t2) != ENUMERAL_TYPE
+ && TREE_CODE (t2) != QUAL_UNION_TYPE
+ && TREE_CODE (t2) != UNION_TYPE)
+ return -1;
+ if (TYPE_SIZE (t2) == 0)
+ return -1;
+ }
+ /* These are the only cases that need special handling. */
+ if (TREE_CODE (t) != RECORD_TYPE
+ && TREE_CODE (t) != ENUMERAL_TYPE
+ && TREE_CODE (t) != QUAL_UNION_TYPE
+ && TREE_CODE (t) != UNION_TYPE
+ && TREE_CODE (t) != POINTER_TYPE)
+ return -1;
+ /* Undefined? */
+ if (TYPE_SIZE (t) == 0)
+ return -1;
+
+ /* Look up t in hash table. Only one of the compatible types within each
+ alias set is recorded in the table. */
+ if (!type_hash_table)
+ type_hash_table = htab_create_ggc (1021, c_type_hash,
+ (htab_eq) lang_hooks.types_compatible_p,
+ NULL);
+ slot = htab_find_slot (type_hash_table, t, INSERT);
+ if (*slot != NULL)
+ {
+ TYPE_ALIAS_SET (t) = TYPE_ALIAS_SET ((tree)*slot);
+ return TYPE_ALIAS_SET ((tree)*slot);
+ }
+ else
+ /* Our caller will assign and record (in t) a new alias set; all we need
+ to do is remember t in the hash table. */
+ *slot = t;
+
return -1;
}
@@ -2936,22 +2896,22 @@ c_common_get_alias_set (tree t)
second parameter indicates which OPERATOR is being applied. The COMPLAIN
flag controls whether we should diagnose possibly ill-formed
constructs or not. */
+
tree
-c_sizeof_or_alignof_type (tree type, enum tree_code op, int complain)
+c_sizeof_or_alignof_type (tree type, bool is_sizeof, int complain)
{
const char *op_name;
tree value = NULL;
enum tree_code type_code = TREE_CODE (type);
- my_friendly_assert (op == SIZEOF_EXPR || op == ALIGNOF_EXPR, 20020720);
- op_name = op == SIZEOF_EXPR ? "sizeof" : "__alignof__";
+ op_name = is_sizeof ? "sizeof" : "__alignof__";
if (type_code == FUNCTION_TYPE)
{
- if (op == SIZEOF_EXPR)
+ if (is_sizeof)
{
if (complain && (pedantic || warn_pointer_arith))
- pedwarn ("invalid application of `sizeof' to a function type");
+ pedwarn ("invalid application of %<sizeof%> to a function type");
value = size_one_node;
}
else
@@ -2961,33 +2921,33 @@ c_sizeof_or_alignof_type (tree type, enum tree_code op, int complain)
{
if (type_code == VOID_TYPE
&& complain && (pedantic || warn_pointer_arith))
- pedwarn ("invalid application of `%s' to a void type", op_name);
+ pedwarn ("invalid application of %qs to a void type", op_name);
value = size_one_node;
}
else if (!COMPLETE_TYPE_P (type))
{
if (complain)
- error ("invalid application of `%s' to incomplete type `%T' ",
+ error ("invalid application of %qs to incomplete type %qT ",
op_name, type);
value = size_zero_node;
}
else
{
- if (op == SIZEOF_EXPR)
+ if (is_sizeof)
/* Convert in case a char is more than one unit. */
value = size_binop (CEIL_DIV_EXPR, TYPE_SIZE_UNIT (type),
size_int (TYPE_PRECISION (char_type_node)
/ BITS_PER_UNIT));
else
- value = size_int (TYPE_ALIGN (type) / BITS_PER_UNIT);
+ value = size_int (TYPE_ALIGN_UNIT (type));
}
/* VALUE will have an integer type with TYPE_IS_SIZETYPE set.
TYPE_IS_SIZETYPE means that certain things (like overflow) will
never happen. However, this node should really have type
`size_t', which is just a typedef for an ordinary integer type. */
- value = fold (build1 (NOP_EXPR, size_type_node, value));
- my_friendly_assert (!TYPE_IS_SIZETYPE (TREE_TYPE (value)), 20001021);
+ value = fold_convert (size_type_node, value);
+ gcc_assert (!TYPE_IS_SIZETYPE (TREE_TYPE (value)));
return value;
}
@@ -3003,17 +2963,17 @@ c_alignof_expr (tree expr)
tree t;
if (TREE_CODE (expr) == VAR_DECL)
- t = size_int (DECL_ALIGN (expr) / BITS_PER_UNIT);
+ t = size_int (DECL_ALIGN_UNIT (expr));
else if (TREE_CODE (expr) == COMPONENT_REF
&& DECL_C_BIT_FIELD (TREE_OPERAND (expr, 1)))
{
- error ("`__alignof' applied to a bit-field");
+ error ("%<__alignof%> applied to a bit-field");
t = size_one_node;
}
else if (TREE_CODE (expr) == COMPONENT_REF
&& TREE_CODE (TREE_OPERAND (expr, 1)) == FIELD_DECL)
- t = size_int (DECL_ALIGN (TREE_OPERAND (expr, 1)) / BITS_PER_UNIT);
+ t = size_int (DECL_ALIGN_UNIT (TREE_OPERAND (expr, 1)));
else if (TREE_CODE (expr) == INDIRECT_REF)
{
@@ -3021,7 +2981,7 @@ c_alignof_expr (tree expr)
tree best = t;
int bestalign = TYPE_ALIGN (TREE_TYPE (TREE_TYPE (t)));
- while (TREE_CODE (t) == NOP_EXPR
+ while ((TREE_CODE (t) == NOP_EXPR || TREE_CODE (t) == CONVERT_EXPR)
&& TREE_CODE (TREE_TYPE (TREE_OPERAND (t, 0))) == POINTER_TYPE)
{
int thisalign;
@@ -3036,7 +2996,7 @@ c_alignof_expr (tree expr)
else
return c_alignof (TREE_TYPE (expr));
- return fold (build1 (NOP_EXPR, size_type_node, t));
+ return fold_convert (size_type_node, t);
}
/* Handle C and C++ default attributes. */
@@ -3059,24 +3019,24 @@ static GTY(()) tree built_in_attributes[(int) ATTR_LAST];
static void c_init_attributes (void);
-/* Build tree nodes and builtin functions common to both C and C++ language
- frontends. */
-
-void
-c_common_nodes_and_builtins (void)
+enum c_builtin_type
{
- enum builtin_type
- {
#define DEF_PRIMITIVE_TYPE(NAME, VALUE) NAME,
#define DEF_FUNCTION_TYPE_0(NAME, RETURN) NAME,
#define DEF_FUNCTION_TYPE_1(NAME, RETURN, ARG1) NAME,
#define DEF_FUNCTION_TYPE_2(NAME, RETURN, ARG1, ARG2) NAME,
#define DEF_FUNCTION_TYPE_3(NAME, RETURN, ARG1, ARG2, ARG3) NAME,
#define DEF_FUNCTION_TYPE_4(NAME, RETURN, ARG1, ARG2, ARG3, ARG4) NAME,
+#define DEF_FUNCTION_TYPE_5(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5) NAME,
+#define DEF_FUNCTION_TYPE_6(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6) NAME,
+#define DEF_FUNCTION_TYPE_7(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6, ARG7) NAME,
#define DEF_FUNCTION_TYPE_VAR_0(NAME, RETURN) NAME,
#define DEF_FUNCTION_TYPE_VAR_1(NAME, RETURN, ARG1) NAME,
#define DEF_FUNCTION_TYPE_VAR_2(NAME, RETURN, ARG1, ARG2) NAME,
#define DEF_FUNCTION_TYPE_VAR_3(NAME, RETURN, ARG1, ARG2, ARG3) NAME,
+#define DEF_FUNCTION_TYPE_VAR_4(NAME, RETURN, ARG1, ARG2, ARG3, ARG4) NAME,
+#define DEF_FUNCTION_TYPE_VAR_5(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG6) \
+ NAME,
#define DEF_POINTER_TYPE(NAME, TYPE) NAME,
#include "builtin-types.def"
#undef DEF_PRIMITIVE_TYPE
@@ -3085,17 +3045,71 @@ c_common_nodes_and_builtins (void)
#undef DEF_FUNCTION_TYPE_2
#undef DEF_FUNCTION_TYPE_3
#undef DEF_FUNCTION_TYPE_4
+#undef DEF_FUNCTION_TYPE_5
+#undef DEF_FUNCTION_TYPE_6
+#undef DEF_FUNCTION_TYPE_7
#undef DEF_FUNCTION_TYPE_VAR_0
#undef DEF_FUNCTION_TYPE_VAR_1
#undef DEF_FUNCTION_TYPE_VAR_2
#undef DEF_FUNCTION_TYPE_VAR_3
+#undef DEF_FUNCTION_TYPE_VAR_4
+#undef DEF_FUNCTION_TYPE_VAR_5
#undef DEF_POINTER_TYPE
- BT_LAST
- };
+ BT_LAST
+};
+
+typedef enum c_builtin_type builtin_type;
+
+/* A temporary array for c_common_nodes_and_builtins. Used in
+ communication with def_fn_type. */
+static tree builtin_types[(int) BT_LAST + 1];
- typedef enum builtin_type builtin_type;
+/* A helper function for c_common_nodes_and_builtins. Build function type
+ for DEF with return type RET and N arguments. If VAR is true, then the
+ function should be variadic after those N arguments.
- tree builtin_types[(int) BT_LAST];
+ Takes special care not to ICE if any of the types involved are
+ error_mark_node, which indicates that said type is not in fact available
+ (see builtin_type_for_size). In which case the function type as a whole
+ should be error_mark_node. */
+
+static void
+def_fn_type (builtin_type def, builtin_type ret, bool var, int n, ...)
+{
+ tree args = NULL, t;
+ va_list list;
+ int i;
+
+ va_start (list, n);
+ for (i = 0; i < n; ++i)
+ {
+ builtin_type a = va_arg (list, builtin_type);
+ t = builtin_types[a];
+ if (t == error_mark_node)
+ goto egress;
+ args = tree_cons (NULL_TREE, t, args);
+ }
+ va_end (list);
+
+ args = nreverse (args);
+ if (!var)
+ args = chainon (args, void_list_node);
+
+ t = builtin_types[ret];
+ if (t == error_mark_node)
+ goto egress;
+ t = build_function_type (t, args);
+
+ egress:
+ builtin_types[def] = t;
+}
+
+/* Build tree nodes and builtin functions common to both C and C++ language
+ frontends. */
+
+void
+c_common_nodes_and_builtins (void)
+{
int wchar_type_size;
tree array_domain_type;
tree va_list_ref_type_node;
@@ -3136,43 +3150,45 @@ c_common_nodes_and_builtins (void)
/* These are types that c_common_type_for_size and
c_common_type_for_mode use. */
- (*lang_hooks.decls.pushdecl) (build_decl (TYPE_DECL, NULL_TREE,
- intQI_type_node));
- (*lang_hooks.decls.pushdecl) (build_decl (TYPE_DECL, NULL_TREE,
- intHI_type_node));
- (*lang_hooks.decls.pushdecl) (build_decl (TYPE_DECL, NULL_TREE,
- intSI_type_node));
- (*lang_hooks.decls.pushdecl) (build_decl (TYPE_DECL, NULL_TREE,
- intDI_type_node));
+ lang_hooks.decls.pushdecl (build_decl (TYPE_DECL, NULL_TREE,
+ intQI_type_node));
+ lang_hooks.decls.pushdecl (build_decl (TYPE_DECL, NULL_TREE,
+ intHI_type_node));
+ lang_hooks.decls.pushdecl (build_decl (TYPE_DECL, NULL_TREE,
+ intSI_type_node));
+ lang_hooks.decls.pushdecl (build_decl (TYPE_DECL, NULL_TREE,
+ intDI_type_node));
#if HOST_BITS_PER_WIDE_INT >= 64
- (*lang_hooks.decls.pushdecl) (build_decl (TYPE_DECL,
- get_identifier ("__int128_t"),
- intTI_type_node));
+ if (targetm.scalar_mode_supported_p (TImode))
+ lang_hooks.decls.pushdecl (build_decl (TYPE_DECL,
+ get_identifier ("__int128_t"),
+ intTI_type_node));
#endif
- (*lang_hooks.decls.pushdecl) (build_decl (TYPE_DECL, NULL_TREE,
- unsigned_intQI_type_node));
- (*lang_hooks.decls.pushdecl) (build_decl (TYPE_DECL, NULL_TREE,
- unsigned_intHI_type_node));
- (*lang_hooks.decls.pushdecl) (build_decl (TYPE_DECL, NULL_TREE,
- unsigned_intSI_type_node));
- (*lang_hooks.decls.pushdecl) (build_decl (TYPE_DECL, NULL_TREE,
- unsigned_intDI_type_node));
+ lang_hooks.decls.pushdecl (build_decl (TYPE_DECL, NULL_TREE,
+ unsigned_intQI_type_node));
+ lang_hooks.decls.pushdecl (build_decl (TYPE_DECL, NULL_TREE,
+ unsigned_intHI_type_node));
+ lang_hooks.decls.pushdecl (build_decl (TYPE_DECL, NULL_TREE,
+ unsigned_intSI_type_node));
+ lang_hooks.decls.pushdecl (build_decl (TYPE_DECL, NULL_TREE,
+ unsigned_intDI_type_node));
#if HOST_BITS_PER_WIDE_INT >= 64
- (*lang_hooks.decls.pushdecl) (build_decl (TYPE_DECL,
- get_identifier ("__uint128_t"),
- unsigned_intTI_type_node));
+ if (targetm.scalar_mode_supported_p (TImode))
+ lang_hooks.decls.pushdecl (build_decl (TYPE_DECL,
+ get_identifier ("__uint128_t"),
+ unsigned_intTI_type_node));
#endif
/* Create the widest literal types. */
widest_integer_literal_type_node
= make_signed_type (HOST_BITS_PER_WIDE_INT * 2);
- (*lang_hooks.decls.pushdecl) (build_decl (TYPE_DECL, NULL_TREE,
- widest_integer_literal_type_node));
+ lang_hooks.decls.pushdecl (build_decl (TYPE_DECL, NULL_TREE,
+ widest_integer_literal_type_node));
widest_unsigned_literal_type_node
= make_unsigned_type (HOST_BITS_PER_WIDE_INT * 2);
- (*lang_hooks.decls.pushdecl) (build_decl (TYPE_DECL, NULL_TREE,
- widest_unsigned_literal_type_node));
+ lang_hooks.decls.pushdecl (build_decl (TYPE_DECL, NULL_TREE,
+ widest_unsigned_literal_type_node));
/* `unsigned long' is the standard type for sizeof.
Note that stddef.h uses `unsigned long',
@@ -3182,81 +3198,48 @@ c_common_nodes_and_builtins (void)
signed_size_type_node = c_common_signed_type (size_type_node);
set_sizetype (size_type_node);
+ pid_type_node =
+ TREE_TYPE (identifier_global_value (get_identifier (PID_TYPE)));
+
build_common_tree_nodes_2 (flag_short_double);
record_builtin_type (RID_FLOAT, NULL, float_type_node);
record_builtin_type (RID_DOUBLE, NULL, double_type_node);
record_builtin_type (RID_MAX, "long double", long_double_type_node);
- (*lang_hooks.decls.pushdecl) (build_decl (TYPE_DECL,
- get_identifier ("complex int"),
- complex_integer_type_node));
- (*lang_hooks.decls.pushdecl) (build_decl (TYPE_DECL,
- get_identifier ("complex float"),
- complex_float_type_node));
- (*lang_hooks.decls.pushdecl) (build_decl (TYPE_DECL,
- get_identifier ("complex double"),
- complex_double_type_node));
- (*lang_hooks.decls.pushdecl)
+ /* Only supported decimal floating point extension if the target
+ actually supports underlying modes. */
+ if (targetm.scalar_mode_supported_p (SDmode)
+ && targetm.scalar_mode_supported_p (DDmode)
+ && targetm.scalar_mode_supported_p (TDmode))
+ {
+ record_builtin_type (RID_DFLOAT32, NULL, dfloat32_type_node);
+ record_builtin_type (RID_DFLOAT64, NULL, dfloat64_type_node);
+ record_builtin_type (RID_DFLOAT128, NULL, dfloat128_type_node);
+ }
+
+ lang_hooks.decls.pushdecl (build_decl (TYPE_DECL,
+ get_identifier ("complex int"),
+ complex_integer_type_node));
+ lang_hooks.decls.pushdecl (build_decl (TYPE_DECL,
+ get_identifier ("complex float"),
+ complex_float_type_node));
+ lang_hooks.decls.pushdecl (build_decl (TYPE_DECL,
+ get_identifier ("complex double"),
+ complex_double_type_node));
+ lang_hooks.decls.pushdecl
(build_decl (TYPE_DECL, get_identifier ("complex long double"),
complex_long_double_type_node));
- /* Types which are common to the fortran compiler and libf2c. When
- changing these, you also need to be concerned with f/com.h. */
-
- if (TYPE_PRECISION (float_type_node)
- == TYPE_PRECISION (long_integer_type_node))
- {
- g77_integer_type_node = long_integer_type_node;
- g77_uinteger_type_node = long_unsigned_type_node;
- }
- else if (TYPE_PRECISION (float_type_node)
- == TYPE_PRECISION (integer_type_node))
- {
- g77_integer_type_node = integer_type_node;
- g77_uinteger_type_node = unsigned_type_node;
- }
- else
- g77_integer_type_node = g77_uinteger_type_node = NULL_TREE;
-
- if (g77_integer_type_node != NULL_TREE)
- {
- (*lang_hooks.decls.pushdecl) (build_decl (TYPE_DECL,
- get_identifier ("__g77_integer"),
- g77_integer_type_node));
- (*lang_hooks.decls.pushdecl) (build_decl (TYPE_DECL,
- get_identifier ("__g77_uinteger"),
- g77_uinteger_type_node));
- }
-
- if (TYPE_PRECISION (float_type_node) * 2
- == TYPE_PRECISION (long_integer_type_node))
- {
- g77_longint_type_node = long_integer_type_node;
- g77_ulongint_type_node = long_unsigned_type_node;
- }
- else if (TYPE_PRECISION (float_type_node) * 2
- == TYPE_PRECISION (long_long_integer_type_node))
- {
- g77_longint_type_node = long_long_integer_type_node;
- g77_ulongint_type_node = long_long_unsigned_type_node;
- }
- else
- g77_longint_type_node = g77_ulongint_type_node = NULL_TREE;
-
- if (g77_longint_type_node != NULL_TREE)
- {
- (*lang_hooks.decls.pushdecl) (build_decl (TYPE_DECL,
- get_identifier ("__g77_longint"),
- g77_longint_type_node));
- (*lang_hooks.decls.pushdecl) (build_decl (TYPE_DECL,
- get_identifier ("__g77_ulongint"),
- g77_ulongint_type_node));
- }
+ if (c_dialect_cxx ())
+ /* For C++, make fileptr_type_node a distinct void * type until
+ FILE type is defined. */
+ fileptr_type_node = build_variant_type_copy (ptr_type_node);
record_builtin_type (RID_VOID, NULL, void_type_node);
- void_zero_node = build_int_2 (0, 0);
+ /* This node must not be shared. */
+ void_zero_node = make_node (INTEGER_CST);
TREE_TYPE (void_zero_node) = void_type_node;
void_list_node = build_void_list_node ();
@@ -3289,7 +3272,7 @@ c_common_nodes_and_builtins (void)
wchar_type_size = TYPE_PRECISION (wchar_type_node);
if (c_dialect_cxx ())
{
- if (TREE_UNSIGNED (wchar_type_node))
+ if (TYPE_UNSIGNED (wchar_type_node))
wchar_type_node = make_unsigned_type (wchar_type_size);
else
wchar_type_node = make_signed_type (wchar_type_size);
@@ -3318,18 +3301,10 @@ c_common_nodes_and_builtins (void)
= TREE_TYPE (identifier_global_value (get_identifier (PTRDIFF_TYPE)));
unsigned_ptrdiff_type_node = c_common_unsigned_type (ptrdiff_type_node);
- (*lang_hooks.decls.pushdecl)
+ lang_hooks.decls.pushdecl
(build_decl (TYPE_DECL, get_identifier ("__builtin_va_list"),
va_list_type_node));
- (*lang_hooks.decls.pushdecl)
- (build_decl (TYPE_DECL, get_identifier ("__builtin_ptrdiff_t"),
- ptrdiff_type_node));
-
- (*lang_hooks.decls.pushdecl)
- (build_decl (TYPE_DECL, get_identifier ("__builtin_size_t"),
- sizetype));
-
if (TREE_CODE (va_list_type_node) == ARRAY_TYPE)
{
va_list_arg_type_node = va_list_ref_type_node =
@@ -3342,137 +3317,121 @@ c_common_nodes_and_builtins (void)
}
#define DEF_PRIMITIVE_TYPE(ENUM, VALUE) \
- builtin_types[(int) ENUM] = VALUE;
-#define DEF_FUNCTION_TYPE_0(ENUM, RETURN) \
- builtin_types[(int) ENUM] \
- = build_function_type (builtin_types[(int) RETURN], \
- void_list_node);
-#define DEF_FUNCTION_TYPE_1(ENUM, RETURN, ARG1) \
- builtin_types[(int) ENUM] \
- = build_function_type (builtin_types[(int) RETURN], \
- tree_cons (NULL_TREE, \
- builtin_types[(int) ARG1], \
- void_list_node));
-#define DEF_FUNCTION_TYPE_2(ENUM, RETURN, ARG1, ARG2) \
- builtin_types[(int) ENUM] \
- = build_function_type \
- (builtin_types[(int) RETURN], \
- tree_cons (NULL_TREE, \
- builtin_types[(int) ARG1], \
- tree_cons (NULL_TREE, \
- builtin_types[(int) ARG2], \
- void_list_node)));
-#define DEF_FUNCTION_TYPE_3(ENUM, RETURN, ARG1, ARG2, ARG3) \
- builtin_types[(int) ENUM] \
- = build_function_type \
- (builtin_types[(int) RETURN], \
- tree_cons (NULL_TREE, \
- builtin_types[(int) ARG1], \
- tree_cons (NULL_TREE, \
- builtin_types[(int) ARG2], \
- tree_cons (NULL_TREE, \
- builtin_types[(int) ARG3], \
- void_list_node))));
-#define DEF_FUNCTION_TYPE_4(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4) \
- builtin_types[(int) ENUM] \
- = build_function_type \
- (builtin_types[(int) RETURN], \
- tree_cons (NULL_TREE, \
- builtin_types[(int) ARG1], \
- tree_cons (NULL_TREE, \
- builtin_types[(int) ARG2], \
- tree_cons \
- (NULL_TREE, \
- builtin_types[(int) ARG3], \
- tree_cons (NULL_TREE, \
- builtin_types[(int) ARG4], \
- void_list_node)))));
-#define DEF_FUNCTION_TYPE_VAR_0(ENUM, RETURN) \
- builtin_types[(int) ENUM] \
- = build_function_type (builtin_types[(int) RETURN], NULL_TREE);
-#define DEF_FUNCTION_TYPE_VAR_1(ENUM, RETURN, ARG1) \
- builtin_types[(int) ENUM] \
- = build_function_type (builtin_types[(int) RETURN], \
- tree_cons (NULL_TREE, \
- builtin_types[(int) ARG1], \
- NULL_TREE));
-
-#define DEF_FUNCTION_TYPE_VAR_2(ENUM, RETURN, ARG1, ARG2) \
- builtin_types[(int) ENUM] \
- = build_function_type \
- (builtin_types[(int) RETURN], \
- tree_cons (NULL_TREE, \
- builtin_types[(int) ARG1], \
- tree_cons (NULL_TREE, \
- builtin_types[(int) ARG2], \
- NULL_TREE)));
-
-#define DEF_FUNCTION_TYPE_VAR_3(ENUM, RETURN, ARG1, ARG2, ARG3) \
- builtin_types[(int) ENUM] \
- = build_function_type \
- (builtin_types[(int) RETURN], \
- tree_cons (NULL_TREE, \
- builtin_types[(int) ARG1], \
- tree_cons (NULL_TREE, \
- builtin_types[(int) ARG2], \
- tree_cons (NULL_TREE, \
- builtin_types[(int) ARG3], \
- NULL_TREE))));
-
-#define DEF_POINTER_TYPE(ENUM, TYPE) \
- builtin_types[(int) ENUM] \
- = build_pointer_type (builtin_types[(int) TYPE]);
+ builtin_types[ENUM] = VALUE;
+#define DEF_FUNCTION_TYPE_0(ENUM, RETURN) \
+ def_fn_type (ENUM, RETURN, 0, 0);
+#define DEF_FUNCTION_TYPE_1(ENUM, RETURN, ARG1) \
+ def_fn_type (ENUM, RETURN, 0, 1, ARG1);
+#define DEF_FUNCTION_TYPE_2(ENUM, RETURN, ARG1, ARG2) \
+ def_fn_type (ENUM, RETURN, 0, 2, ARG1, ARG2);
+#define DEF_FUNCTION_TYPE_3(ENUM, RETURN, ARG1, ARG2, ARG3) \
+ def_fn_type (ENUM, RETURN, 0, 3, ARG1, ARG2, ARG3);
+#define DEF_FUNCTION_TYPE_4(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4) \
+ def_fn_type (ENUM, RETURN, 0, 4, ARG1, ARG2, ARG3, ARG4);
+#define DEF_FUNCTION_TYPE_5(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5) \
+ def_fn_type (ENUM, RETURN, 0, 5, ARG1, ARG2, ARG3, ARG4, ARG5);
+#define DEF_FUNCTION_TYPE_6(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \
+ ARG6) \
+ def_fn_type (ENUM, RETURN, 0, 6, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6);
+#define DEF_FUNCTION_TYPE_7(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \
+ ARG6, ARG7) \
+ def_fn_type (ENUM, RETURN, 0, 7, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6, ARG7);
+#define DEF_FUNCTION_TYPE_VAR_0(ENUM, RETURN) \
+ def_fn_type (ENUM, RETURN, 1, 0);
+#define DEF_FUNCTION_TYPE_VAR_1(ENUM, RETURN, ARG1) \
+ def_fn_type (ENUM, RETURN, 1, 1, ARG1);
+#define DEF_FUNCTION_TYPE_VAR_2(ENUM, RETURN, ARG1, ARG2) \
+ def_fn_type (ENUM, RETURN, 1, 2, ARG1, ARG2);
+#define DEF_FUNCTION_TYPE_VAR_3(ENUM, RETURN, ARG1, ARG2, ARG3) \
+ def_fn_type (ENUM, RETURN, 1, 3, ARG1, ARG2, ARG3);
+#define DEF_FUNCTION_TYPE_VAR_4(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4) \
+ def_fn_type (ENUM, RETURN, 1, 4, ARG1, ARG2, ARG3, ARG4);
+#define DEF_FUNCTION_TYPE_VAR_5(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5) \
+ def_fn_type (ENUM, RETURN, 1, 5, ARG1, ARG2, ARG3, ARG4, ARG5);
+#define DEF_POINTER_TYPE(ENUM, TYPE) \
+ builtin_types[(int) ENUM] = build_pointer_type (builtin_types[(int) TYPE]);
+
#include "builtin-types.def"
+
#undef DEF_PRIMITIVE_TYPE
#undef DEF_FUNCTION_TYPE_1
#undef DEF_FUNCTION_TYPE_2
#undef DEF_FUNCTION_TYPE_3
#undef DEF_FUNCTION_TYPE_4
+#undef DEF_FUNCTION_TYPE_5
+#undef DEF_FUNCTION_TYPE_6
#undef DEF_FUNCTION_TYPE_VAR_0
#undef DEF_FUNCTION_TYPE_VAR_1
#undef DEF_FUNCTION_TYPE_VAR_2
#undef DEF_FUNCTION_TYPE_VAR_3
+#undef DEF_FUNCTION_TYPE_VAR_4
+#undef DEF_FUNCTION_TYPE_VAR_5
#undef DEF_POINTER_TYPE
+ builtin_types[(int) BT_LAST] = NULL_TREE;
c_init_attributes ();
-#define DEF_BUILTIN(ENUM, NAME, CLASS, TYPE, LIBTYPE, \
- BOTH_P, FALLBACK_P, NONANSI_P, ATTRS, IMPLICIT) \
- if (NAME) \
- { \
- tree decl; \
- \
- if (strncmp (NAME, "__builtin_", strlen ("__builtin_")) != 0) \
- abort (); \
- \
- if (!BOTH_P) \
- decl = builtin_function (NAME, builtin_types[TYPE], ENUM, \
- CLASS, \
- (FALLBACK_P \
- ? (NAME + strlen ("__builtin_")) \
- : NULL), \
- built_in_attributes[(int) ATTRS]); \
- else \
- decl = builtin_function_2 (NAME, \
- NAME + strlen ("__builtin_"), \
- builtin_types[TYPE], \
- builtin_types[LIBTYPE], \
- ENUM, \
- CLASS, \
- FALLBACK_P, \
- NONANSI_P, \
- built_in_attributes[(int) ATTRS]); \
- \
- built_in_decls[(int) ENUM] = decl; \
- if (IMPLICIT) \
- implicit_built_in_decls[(int) ENUM] = decl; \
- }
+#define DEF_BUILTIN(ENUM, NAME, CLASS, TYPE, LIBTYPE, BOTH_P, FALLBACK_P, \
+ NONANSI_P, ATTRS, IMPLICIT, COND) \
+ if (NAME && COND) \
+ def_builtin_1 (ENUM, NAME, CLASS, \
+ builtin_types[(int) TYPE], \
+ builtin_types[(int) LIBTYPE], \
+ BOTH_P, FALLBACK_P, NONANSI_P, \
+ built_in_attributes[(int) ATTRS], IMPLICIT);
#include "builtins.def"
#undef DEF_BUILTIN
- (*targetm.init_builtins) ();
+ build_common_builtin_nodes ();
+
+ targetm.init_builtins ();
+ if (flag_mudflap)
+ mudflap_init ();
main_identifier_node = get_identifier ("main");
+
+ /* Create the built-in __null node. It is important that this is
+ not shared. */
+ null_node = make_node (INTEGER_CST);
+ TREE_TYPE (null_node) = c_common_type_for_size (POINTER_SIZE, 0);
+
+ /* Since builtin_types isn't gc'ed, don't export these nodes. */
+ memset (builtin_types, 0, sizeof (builtin_types));
+}
+
+/* Look up the function in built_in_decls that corresponds to DECL
+ and set ASMSPEC as its user assembler name. DECL must be a
+ function decl that declares a builtin. */
+
+void
+set_builtin_user_assembler_name (tree decl, const char *asmspec)
+{
+ tree builtin;
+ gcc_assert (TREE_CODE (decl) == FUNCTION_DECL
+ && DECL_BUILT_IN_CLASS (decl) == BUILT_IN_NORMAL
+ && asmspec != 0);
+
+ builtin = built_in_decls [DECL_FUNCTION_CODE (decl)];
+ set_user_assembler_name (builtin, asmspec);
+ if (DECL_FUNCTION_CODE (decl) == BUILT_IN_MEMCPY)
+ init_block_move_fn (asmspec);
+ else if (DECL_FUNCTION_CODE (decl) == BUILT_IN_MEMSET)
+ init_block_clear_fn (asmspec);
+}
+
+/* The number of named compound-literals generated thus far. */
+static GTY(()) int compound_literal_number;
+
+/* Set DECL_NAME for DECL, a VAR_DECL for a compound-literal. */
+
+void
+set_compound_literal_name (tree decl)
+{
+ char *name;
+ ASM_FORMAT_PRIVATE_NAME (name, "__compound_literal",
+ compound_literal_number);
+ compound_literal_number++;
+ DECL_NAME (decl) = get_identifier (name);
}
tree
@@ -3500,13 +3459,13 @@ void
disable_builtin_function (const char *name)
{
if (strncmp (name, "__builtin_", strlen ("__builtin_")) == 0)
- error ("cannot disable built-in function `%s'", name);
+ error ("cannot disable built-in function %qs", name);
else
{
- disabled_builtin *new = xmalloc (sizeof (disabled_builtin));
- new->name = name;
- new->next = disabled_builtins;
- disabled_builtins = new;
+ disabled_builtin *new_disabled_builtin = XNEW (disabled_builtin);
+ new_disabled_builtin->name = name;
+ new_disabled_builtin->next = disabled_builtins;
+ disabled_builtins = new_disabled_builtin;
}
}
@@ -3527,39 +3486,42 @@ builtin_function_disabled_p (const char *name)
}
-/* Possibly define a builtin function with one or two names. BUILTIN_NAME
- is an __builtin_-prefixed name; NAME is the ordinary name; one or both
- of these may be NULL (though both being NULL is useless).
- BUILTIN_TYPE is the type of the __builtin_-prefixed function;
- TYPE is the type of the function with the ordinary name. These
- may differ if the ordinary name is declared with a looser type to avoid
- conflicts with headers. FUNCTION_CODE and CLASS are as for
- builtin_function. If LIBRARY_NAME_P is nonzero, NAME is passed as
- the LIBRARY_NAME parameter to builtin_function when declaring BUILTIN_NAME.
- If NONANSI_P is nonzero, the name NAME is treated as a non-ANSI name;
- ATTRS is the tree list representing the builtin's function attributes.
- Returns the declaration of BUILTIN_NAME, if any, otherwise
- the declaration of NAME. Does not declare NAME if flag_no_builtin,
- or if NONANSI_P and flag_no_nonansi_builtin. */
+/* Worker for DEF_BUILTIN.
+ Possibly define a builtin function with one or two names.
+ Does not declare a non-__builtin_ function if flag_no_builtin, or if
+ nonansi_p and flag_no_nonansi_builtin. */
-static tree
-builtin_function_2 (const char *builtin_name, const char *name,
- tree builtin_type, tree type, int function_code,
- enum built_in_class class, int library_name_p,
- int nonansi_p, tree attrs)
+static void
+def_builtin_1 (enum built_in_function fncode,
+ const char *name,
+ enum built_in_class fnclass,
+ tree fntype, tree libtype,
+ bool both_p, bool fallback_p, bool nonansi_p,
+ tree fnattrs, bool implicit_p)
{
- tree bdecl = NULL_TREE;
- tree decl = NULL_TREE;
+ tree decl;
+ const char *libname;
+
+ if (fntype == error_mark_node)
+ return;
- if (builtin_name != 0)
- bdecl = builtin_function (builtin_name, builtin_type, function_code,
- class, library_name_p ? name : NULL, attrs);
+ gcc_assert ((!both_p && !fallback_p)
+ || !strncmp (name, "__builtin_",
+ strlen ("__builtin_")));
- if (name != 0 && !flag_no_builtin && !builtin_function_disabled_p (name)
+ libname = name + strlen ("__builtin_");
+ decl = lang_hooks.builtin_function (name, fntype, fncode, fnclass,
+ (fallback_p ? libname : NULL),
+ fnattrs);
+ if (both_p
+ && !flag_no_builtin && !builtin_function_disabled_p (libname)
&& !(nonansi_p && flag_no_nonansi_builtin))
- decl = builtin_function (name, type, function_code, class, NULL, attrs);
+ lang_hooks.builtin_function (libname, libtype, fncode, fnclass,
+ NULL, fnattrs);
- return (bdecl != 0 ? bdecl : decl);
+ built_in_decls[(int) fncode] = decl;
+ if (implicit_p)
+ implicit_built_in_decls[(int) fncode] = decl;
}
/* Nonzero if the type T promotes to int. This is (nearly) the
@@ -3603,6 +3565,9 @@ self_promoting_args_p (tree parms)
{
tree type = TREE_VALUE (t);
+ if (type == error_mark_node)
+ continue;
+
if (TREE_CHAIN (t) == 0 && type != void_type_node)
return 0;
@@ -3639,225 +3604,6 @@ strip_pointer_operator (tree t)
return t;
}
-static tree expand_unordered_cmp (tree, tree, enum tree_code, enum tree_code);
-
-/* Expand a call to an unordered comparison function such as
- __builtin_isgreater(). FUNCTION is the function's declaration and
- PARAMS a list of the values passed. For __builtin_isunordered(),
- UNORDERED_CODE is UNORDERED_EXPR and ORDERED_CODE is NOP_EXPR. In
- other cases, UNORDERED_CODE and ORDERED_CODE are comparison codes
- that give the opposite of the desired result. UNORDERED_CODE is
- used for modes that can hold NaNs and ORDERED_CODE is used for the
- rest. */
-
-static tree
-expand_unordered_cmp (tree function, tree params,
- enum tree_code unordered_code,
- enum tree_code ordered_code)
-{
- tree arg0, arg1, type;
- enum tree_code code0, code1;
-
- /* Check that we have exactly two arguments. */
- if (params == 0 || TREE_CHAIN (params) == 0)
- {
- error ("too few arguments to function `%s'",
- IDENTIFIER_POINTER (DECL_NAME (function)));
- return error_mark_node;
- }
- else if (TREE_CHAIN (TREE_CHAIN (params)) != 0)
- {
- error ("too many arguments to function `%s'",
- IDENTIFIER_POINTER (DECL_NAME (function)));
- return error_mark_node;
- }
-
- arg0 = TREE_VALUE (params);
- arg1 = TREE_VALUE (TREE_CHAIN (params));
-
- code0 = TREE_CODE (TREE_TYPE (arg0));
- code1 = TREE_CODE (TREE_TYPE (arg1));
-
- /* Make sure that the arguments have a common type of REAL. */
- type = 0;
- if ((code0 == INTEGER_TYPE || code0 == REAL_TYPE)
- && (code1 == INTEGER_TYPE || code1 == REAL_TYPE))
- type = common_type (TREE_TYPE (arg0), TREE_TYPE (arg1));
-
- if (type == 0 || TREE_CODE (type) != REAL_TYPE)
- {
- error ("non-floating-point argument to function `%s'",
- IDENTIFIER_POINTER (DECL_NAME (function)));
- return error_mark_node;
- }
-
- if (unordered_code == UNORDERED_EXPR)
- {
- if (MODE_HAS_NANS (TYPE_MODE (type)))
- return build_binary_op (unordered_code,
- convert (type, arg0),
- convert (type, arg1),
- 0);
- else
- return integer_zero_node;
- }
-
- return build_unary_op (TRUTH_NOT_EXPR,
- build_binary_op (MODE_HAS_NANS (TYPE_MODE (type))
- ? unordered_code
- : ordered_code,
- convert (type, arg0),
- convert (type, arg1),
- 0),
- 0);
-}
-
-
-/* Recognize certain built-in functions so we can make tree-codes
- other than CALL_EXPR. We do this when it enables fold-const.c
- to do something useful. */
-/* ??? By rights this should go in builtins.c, but only C and C++
- implement build_{binary,unary}_op. Not exactly sure what bits
- of functionality are actually needed from those functions, or
- where the similar functionality exists in the other front ends. */
-
-tree
-expand_tree_builtin (tree function, tree params, tree coerced_params)
-{
- if (DECL_BUILT_IN_CLASS (function) != BUILT_IN_NORMAL)
- return NULL_TREE;
-
- switch (DECL_FUNCTION_CODE (function))
- {
- case BUILT_IN_ABS:
- case BUILT_IN_LABS:
- case BUILT_IN_LLABS:
- case BUILT_IN_IMAXABS:
- case BUILT_IN_FABS:
- case BUILT_IN_FABSL:
- case BUILT_IN_FABSF:
- if (coerced_params == 0)
- return integer_zero_node;
- return build_unary_op (ABS_EXPR, TREE_VALUE (coerced_params), 0);
-
- case BUILT_IN_CONJ:
- case BUILT_IN_CONJF:
- case BUILT_IN_CONJL:
- if (coerced_params == 0)
- return integer_zero_node;
- return build_unary_op (CONJ_EXPR, TREE_VALUE (coerced_params), 0);
-
- case BUILT_IN_CREAL:
- case BUILT_IN_CREALF:
- case BUILT_IN_CREALL:
- if (coerced_params == 0)
- return integer_zero_node;
- return non_lvalue (build_unary_op (REALPART_EXPR,
- TREE_VALUE (coerced_params), 0));
-
- case BUILT_IN_CIMAG:
- case BUILT_IN_CIMAGF:
- case BUILT_IN_CIMAGL:
- if (coerced_params == 0)
- return integer_zero_node;
- return non_lvalue (build_unary_op (IMAGPART_EXPR,
- TREE_VALUE (coerced_params), 0));
-
- case BUILT_IN_ISGREATER:
- return expand_unordered_cmp (function, params, UNLE_EXPR, LE_EXPR);
-
- case BUILT_IN_ISGREATEREQUAL:
- return expand_unordered_cmp (function, params, UNLT_EXPR, LT_EXPR);
-
- case BUILT_IN_ISLESS:
- return expand_unordered_cmp (function, params, UNGE_EXPR, GE_EXPR);
-
- case BUILT_IN_ISLESSEQUAL:
- return expand_unordered_cmp (function, params, UNGT_EXPR, GT_EXPR);
-
- case BUILT_IN_ISLESSGREATER:
- return expand_unordered_cmp (function, params, UNEQ_EXPR, EQ_EXPR);
-
- case BUILT_IN_ISUNORDERED:
- return expand_unordered_cmp (function, params, UNORDERED_EXPR, NOP_EXPR);
-
- default:
- break;
- }
-
- return NULL_TREE;
-}
-
-/* Walk the statement tree, rooted at *tp. Apply FUNC to all the
- sub-trees of *TP in a pre-order traversal. FUNC is called with the
- DATA and the address of each sub-tree. If FUNC returns a non-NULL
- value, the traversal is aborted, and the value returned by FUNC is
- returned. If FUNC sets WALK_SUBTREES to zero, then the subtrees of
- the node being visited are not walked.
-
- We don't need a without_duplicates variant of this one because the
- statement tree is a tree, not a graph. */
-
-tree
-walk_stmt_tree (tree *tp, walk_tree_fn func, void *data)
-{
- enum tree_code code;
- int walk_subtrees;
- tree result;
- int i, len;
-
-#define WALK_SUBTREE(NODE) \
- do \
- { \
- result = walk_stmt_tree (&(NODE), func, data); \
- if (result) \
- return result; \
- } \
- while (0)
-
- /* Skip empty subtrees. */
- if (!*tp)
- return NULL_TREE;
-
- /* Skip subtrees below non-statement nodes. */
- if (!STATEMENT_CODE_P (TREE_CODE (*tp)))
- return NULL_TREE;
-
- /* Call the function. */
- walk_subtrees = 1;
- result = (*func) (tp, &walk_subtrees, data);
-
- /* If we found something, return it. */
- if (result)
- return result;
-
- /* FUNC may have modified the tree, recheck that we're looking at a
- statement node. */
- code = TREE_CODE (*tp);
- if (!STATEMENT_CODE_P (code))
- return NULL_TREE;
-
- /* Visit the subtrees unless FUNC decided that there was nothing
- interesting below this point in the tree. */
- if (walk_subtrees)
- {
- /* Walk over all the sub-trees of this operand. Statement nodes
- never contain RTL, and we needn't worry about TARGET_EXPRs. */
- len = TREE_CODE_LENGTH (code);
-
- /* Go through the subtrees. We need to do this in forward order so
- that the scope of a FOR_EXPR is handled properly. */
- for (i = 0; i < len; ++i)
- WALK_SUBTREE (TREE_OPERAND (*tp, i));
- }
-
- /* Finally visit the chain. This can be tail-recursion optimized if
- we write it this way. */
- return walk_stmt_tree (&TREE_CHAIN (*tp), func, data);
-
-#undef WALK_SUBTREE
-}
-
/* Used to compare case labels. K1 and K2 are actually tree nodes
representing case labels, or NULL_TREE for a `default' label.
Returns -1 if K1 is ordered before K2, -1 if K1 is ordered after
@@ -3882,12 +3628,12 @@ case_compare (splay_tree_key k1, splay_tree_key k2)
case label was declared using the usual C/C++ syntax, rather than
the GNU case range extension. CASES is a tree containing all the
case ranges processed so far; COND is the condition for the
- switch-statement itself. Returns the CASE_LABEL created, or
- ERROR_MARK_NODE if no CASE_LABEL is created. */
+ switch-statement itself. Returns the CASE_LABEL_EXPR created, or
+ ERROR_MARK_NODE if no CASE_LABEL_EXPR is created. */
tree
-c_add_case_label (splay_tree cases, tree cond, tree low_value,
- tree high_value)
+c_add_case_label (splay_tree cases, tree cond, tree orig_type,
+ tree low_value, tree high_value)
{
tree type;
tree label;
@@ -3895,25 +3641,21 @@ c_add_case_label (splay_tree cases, tree cond, tree low_value,
splay_tree_node node;
/* Create the LABEL_DECL itself. */
- label = build_decl (LABEL_DECL, NULL_TREE, NULL_TREE);
- DECL_CONTEXT (label) = current_function_decl;
+ label = create_artificial_label ();
/* If there was an error processing the switch condition, bail now
before we get more confused. */
if (!cond || cond == error_mark_node)
- {
- /* Add a label anyhow so that the back-end doesn't think that
- the beginning of the switch is unreachable. */
- if (!cases->root)
- add_stmt (build_case_label (NULL_TREE, NULL_TREE, label));
- return error_mark_node;
- }
+ goto error_out;
if ((low_value && TREE_TYPE (low_value)
&& POINTER_TYPE_P (TREE_TYPE (low_value)))
|| (high_value && TREE_TYPE (high_value)
&& POINTER_TYPE_P (TREE_TYPE (high_value))))
- error ("pointers are not permitted as case values");
+ {
+ error ("pointers are not permitted as case values");
+ goto error_out;
+ }
/* Case ranges are a GNU extension. */
if (high_value && pedantic)
@@ -3924,29 +3666,35 @@ c_add_case_label (splay_tree cases, tree cond, tree low_value,
{
low_value = check_case_value (low_value);
low_value = convert_and_check (type, low_value);
+ if (low_value == error_mark_node)
+ goto error_out;
}
if (high_value)
{
high_value = check_case_value (high_value);
high_value = convert_and_check (type, high_value);
+ if (high_value == error_mark_node)
+ goto error_out;
}
- /* If an error has occurred, bail out now. */
- if (low_value == error_mark_node || high_value == error_mark_node)
+ if (low_value && high_value)
{
- if (!cases->root)
- add_stmt (build_case_label (NULL_TREE, NULL_TREE, label));
- return error_mark_node;
+ /* If the LOW_VALUE and HIGH_VALUE are the same, then this isn't
+ really a case range, even though it was written that way.
+ Remove the HIGH_VALUE to simplify later processing. */
+ if (tree_int_cst_equal (low_value, high_value))
+ high_value = NULL_TREE;
+ else if (!tree_int_cst_lt (low_value, high_value))
+ warning (0, "empty range specified");
}
- /* If the LOW_VALUE and HIGH_VALUE are the same, then this isn't
- really a case range, even though it was written that way. Remove
- the HIGH_VALUE to simplify later processing. */
- if (tree_int_cst_equal (low_value, high_value))
- high_value = NULL_TREE;
- if (low_value && high_value
- && !tree_int_cst_lt (low_value, high_value))
- warning ("empty range specified");
+ /* See if the case is in range of the type of the original testing
+ expression. If both low_value and high_value are out of range,
+ don't insert the case label and return NULL_TREE. */
+ if (low_value
+ && !check_case_bounds (type, orig_type,
+ &low_value, high_value ? &high_value : NULL))
+ return NULL_TREE;
/* Look up the LOW_VALUE in the table of case labels we already
have. */
@@ -3993,7 +3741,7 @@ c_add_case_label (splay_tree cases, tree cond, tree low_value,
/* If there was an overlap, issue an error. */
if (node)
{
- tree duplicate = CASE_LABEL_DECL ((tree) node->value);
+ tree duplicate = CASE_LABEL ((tree) node->value);
if (high_value)
{
@@ -4010,8 +3758,7 @@ c_add_case_label (splay_tree cases, tree cond, tree low_value,
error ("multiple default labels in one switch");
error ("%Jthis is the first default label", duplicate);
}
- if (!cases->root)
- add_stmt (build_case_label (NULL_TREE, NULL_TREE, label));
+ goto error_out;
}
/* Add a CASE_LABEL to the statement-tree. */
@@ -4022,6 +3769,179 @@ c_add_case_label (splay_tree cases, tree cond, tree low_value,
(splay_tree_value) case_label);
return case_label;
+
+ error_out:
+ /* Add a label so that the back-end doesn't think that the beginning of
+ the switch is unreachable. Note that we do not add a case label, as
+ that just leads to duplicates and thence to failure later on. */
+ if (!cases->root)
+ {
+ tree t = create_artificial_label ();
+ add_stmt (build_stmt (LABEL_EXPR, t));
+ }
+ return error_mark_node;
+}
+
+/* Subroutines of c_do_switch_warnings, called via splay_tree_foreach.
+ Used to verify that case values match up with enumerator values. */
+
+static void
+match_case_to_enum_1 (tree key, tree type, tree label)
+{
+ char buf[2 + 2*HOST_BITS_PER_WIDE_INT/4 + 1];
+
+ /* ??? Not working too hard to print the double-word value.
+ Should perhaps be done with %lwd in the diagnostic routines? */
+ if (TREE_INT_CST_HIGH (key) == 0)
+ snprintf (buf, sizeof (buf), HOST_WIDE_INT_PRINT_UNSIGNED,
+ TREE_INT_CST_LOW (key));
+ else if (!TYPE_UNSIGNED (type)
+ && TREE_INT_CST_HIGH (key) == -1
+ && TREE_INT_CST_LOW (key) != 0)
+ snprintf (buf, sizeof (buf), "-" HOST_WIDE_INT_PRINT_UNSIGNED,
+ -TREE_INT_CST_LOW (key));
+ else
+ snprintf (buf, sizeof (buf), HOST_WIDE_INT_PRINT_DOUBLE_HEX,
+ TREE_INT_CST_HIGH (key), TREE_INT_CST_LOW (key));
+
+ if (TYPE_NAME (type) == 0)
+ warning (0, "%Jcase value %qs not in enumerated type",
+ CASE_LABEL (label), buf);
+ else
+ warning (0, "%Jcase value %qs not in enumerated type %qT",
+ CASE_LABEL (label), buf, type);
+}
+
+/* Subroutine of c_do_switch_warnings, called via splay_tree_foreach.
+ Used to verify that case values match up with enumerator values. */
+
+static int
+match_case_to_enum (splay_tree_node node, void *data)
+{
+ tree label = (tree) node->value;
+ tree type = (tree) data;
+
+ /* Skip default case. */
+ if (!CASE_LOW (label))
+ return 0;
+
+ /* If CASE_LOW_SEEN is not set, that means CASE_LOW did not appear
+ when we did our enum->case scan. Reset our scratch bit after. */
+ if (!CASE_LOW_SEEN (label))
+ match_case_to_enum_1 (CASE_LOW (label), type, label);
+ else
+ CASE_LOW_SEEN (label) = 0;
+
+ /* If CASE_HIGH is non-null, we have a range. If CASE_HIGH_SEEN is
+ not set, that means that CASE_HIGH did not appear when we did our
+ enum->case scan. Reset our scratch bit after. */
+ if (CASE_HIGH (label))
+ {
+ if (!CASE_HIGH_SEEN (label))
+ match_case_to_enum_1 (CASE_HIGH (label), type, label);
+ else
+ CASE_HIGH_SEEN (label) = 0;
+ }
+
+ return 0;
+}
+
+/* Handle -Wswitch*. Called from the front end after parsing the
+ switch construct. */
+/* ??? Should probably be somewhere generic, since other languages
+ besides C and C++ would want this. At the moment, however, C/C++
+ are the only tree-ssa languages that support enumerations at all,
+ so the point is moot. */
+
+void
+c_do_switch_warnings (splay_tree cases, location_t switch_location,
+ tree type, tree cond)
+{
+ splay_tree_node default_node;
+ splay_tree_node node;
+ tree chain;
+
+ if (!warn_switch && !warn_switch_enum && !warn_switch_default)
+ return;
+
+ default_node = splay_tree_lookup (cases, (splay_tree_key) NULL);
+ if (!default_node)
+ warning (OPT_Wswitch_default, "%Hswitch missing default case",
+ &switch_location);
+
+ /* From here on, we only care about about enumerated types. */
+ if (!type || TREE_CODE (type) != ENUMERAL_TYPE)
+ return;
+
+ /* If the switch expression was an enumerated type, check that
+ exactly all enumeration literals are covered by the cases.
+ The check is made when -Wswitch was specified and there is no
+ default case, or when -Wswitch-enum was specified. */
+
+ if (!warn_switch_enum
+ && !(warn_switch && !default_node))
+ return;
+
+ /* Clearing COND if it is not an integer constant simplifies
+ the tests inside the loop below. */
+ if (TREE_CODE (cond) != INTEGER_CST)
+ cond = NULL_TREE;
+
+ /* The time complexity here is O(N*lg(N)) worst case, but for the
+ common case of monotonically increasing enumerators, it is
+ O(N), since the nature of the splay tree will keep the next
+ element adjacent to the root at all times. */
+
+ for (chain = TYPE_VALUES (type); chain; chain = TREE_CHAIN (chain))
+ {
+ tree value = TREE_VALUE (chain);
+ node = splay_tree_lookup (cases, (splay_tree_key) value);
+ if (node)
+ {
+ /* Mark the CASE_LOW part of the case entry as seen. */
+ tree label = (tree) node->value;
+ CASE_LOW_SEEN (label) = 1;
+ continue;
+ }
+
+ /* Even though there wasn't an exact match, there might be a
+ case range which includes the enumator's value. */
+ node = splay_tree_predecessor (cases, (splay_tree_key) value);
+ if (node && CASE_HIGH ((tree) node->value))
+ {
+ tree label = (tree) node->value;
+ int cmp = tree_int_cst_compare (CASE_HIGH (label), value);
+ if (cmp >= 0)
+ {
+ /* If we match the upper bound exactly, mark the CASE_HIGH
+ part of the case entry as seen. */
+ if (cmp == 0)
+ CASE_HIGH_SEEN (label) = 1;
+ continue;
+ }
+ }
+
+ /* We've now determined that this enumerated literal isn't
+ handled by the case labels of the switch statement. */
+
+ /* If the switch expression is a constant, we only really care
+ about whether that constant is handled by the switch. */
+ if (cond && tree_int_cst_compare (cond, value))
+ continue;
+
+ warning (0, "%Henumeration value %qE not handled in switch",
+ &switch_location, TREE_PURPOSE (chain));
+ }
+
+ /* Warn if there are case expressions that don't correspond to
+ enumerators. This can occur since C and C++ don't enforce
+ type-checking of assignments to enumeration variables.
+
+ The time complexity here is now always O(N) worst case, since
+ we should have marked both the lower bound and upper bound of
+ every disjoint case label, with CASE_LOW_SEEN and CASE_HIGH_SEEN
+ above. This scan also resets those fields. */
+ splay_tree_foreach (cases, match_case_to_enum, type);
}
/* Finish an expression taking the address of LABEL (an
@@ -4045,7 +3965,6 @@ finish_label_address_expr (tree label)
{
TREE_USED (label) = 1;
result = build1 (ADDR_EXPR, ptr_type_node, label);
- TREE_CONSTANT (result) = 1;
/* The current function in not necessarily uninlinable.
Computed gotos are incompatible with inlining, but the value
here could be used only in a diagnostic, for example. */
@@ -4055,96 +3974,17 @@ finish_label_address_expr (tree label)
}
/* Hook used by expand_expr to expand language-specific tree codes. */
+/* The only things that should go here are bits needed to expand
+ constant initializers. Everything else should be handled by the
+ gimplification routines. */
rtx
-c_expand_expr (tree exp, rtx target, enum machine_mode tmode,
+c_expand_expr (tree exp, rtx target, enum machine_mode tmode,
int modifier /* Actually enum_modifier. */,
rtx *alt_rtl)
{
switch (TREE_CODE (exp))
{
- case STMT_EXPR:
- {
- tree rtl_expr;
- rtx result;
- bool preserve_result = false;
-
- if (STMT_EXPR_WARN_UNUSED_RESULT (exp) && target == const0_rtx)
- {
- tree stmt = STMT_EXPR_STMT (exp);
- tree scope;
-
- for (scope = COMPOUND_BODY (stmt);
- scope && TREE_CODE (scope) != SCOPE_STMT;
- scope = TREE_CHAIN (scope));
-
- if (scope && SCOPE_STMT_BLOCK (scope))
- warning ("%Hignoring return value of `%D', "
- "declared with attribute warn_unused_result",
- &expr_wfl_stack->location,
- BLOCK_ABSTRACT_ORIGIN (SCOPE_STMT_BLOCK (scope)));
- else
- warning ("%Hignoring return value of function "
- "declared with attribute warn_unused_result",
- &expr_wfl_stack->location);
- }
-
- /* Since expand_expr_stmt calls free_temp_slots after every
- expression statement, we must call push_temp_slots here.
- Otherwise, any temporaries in use now would be considered
- out-of-scope after the first EXPR_STMT from within the
- STMT_EXPR. */
- push_temp_slots ();
- rtl_expr = expand_start_stmt_expr (!STMT_EXPR_NO_SCOPE (exp));
-
- /* If we want the result of this expression, find the last
- EXPR_STMT in the COMPOUND_STMT and mark it as addressable. */
- if (target != const0_rtx
- && TREE_CODE (STMT_EXPR_STMT (exp)) == COMPOUND_STMT
- && TREE_CODE (COMPOUND_BODY (STMT_EXPR_STMT (exp))) == SCOPE_STMT)
- {
- tree expr = COMPOUND_BODY (STMT_EXPR_STMT (exp));
- tree last = TREE_CHAIN (expr);
-
- while (TREE_CHAIN (last))
- {
- expr = last;
- last = TREE_CHAIN (last);
- }
-
- if (TREE_CODE (last) == SCOPE_STMT
- && TREE_CODE (expr) == EXPR_STMT)
- {
- /* Otherwise, note that we want the value from the last
- expression. */
- TREE_ADDRESSABLE (expr) = 1;
- preserve_result = true;
- }
- }
-
- expand_stmt (STMT_EXPR_STMT (exp));
- expand_end_stmt_expr (rtl_expr);
-
- result = expand_expr_real (rtl_expr, target, tmode, modifier, alt_rtl);
- if (preserve_result && GET_CODE (result) == MEM)
- {
- if (GET_MODE (result) != BLKmode)
- result = copy_to_reg (result);
- else
- preserve_temp_slots (result);
- }
-
- /* If the statment-expression does not have a scope, then the
- new temporaries we created within it must live beyond the
- statement-expression. */
- if (STMT_EXPR_NO_SCOPE (exp))
- preserve_temp_slots (NULL_RTX);
-
- pop_temp_slots ();
- return result;
- }
- break;
-
case COMPOUND_LITERAL_EXPR:
{
/* Initialize the anonymous variable declared in the compound
@@ -4155,63 +3995,18 @@ c_expand_expr (tree exp, rtx target, enum machine_mode tmode,
}
default:
- abort ();
- }
-
- abort ();
- return NULL;
-}
-
-/* Hook used by safe_from_p to handle language-specific tree codes. */
-
-int
-c_safe_from_p (rtx target, tree exp)
-{
- /* We can see statements here when processing the body of a
- statement-expression. For a declaration statement declaring a
- variable, look at the variable's initializer. */
- if (TREE_CODE (exp) == DECL_STMT)
- {
- tree decl = DECL_STMT_DECL (exp);
-
- if (TREE_CODE (decl) == VAR_DECL
- && DECL_INITIAL (decl)
- && !safe_from_p (target, DECL_INITIAL (decl), /*top_p=*/0))
- return 0;
+ gcc_unreachable ();
}
-
- /* For any statement, we must follow the statement-chain. */
- if (STATEMENT_CODE_P (TREE_CODE (exp)) && TREE_CHAIN (exp))
- return safe_from_p (target, TREE_CHAIN (exp), /*top_p=*/0);
-
- /* Assume everything else is safe. */
- return 1;
-}
-
-/* Hook used by unsafe_for_reeval to handle language-specific tree codes. */
-
-int
-c_common_unsafe_for_reeval (tree exp)
-{
- /* Statement expressions may not be reevaluated, likewise compound
- literals. */
- if (TREE_CODE (exp) == STMT_EXPR
- || TREE_CODE (exp) == COMPOUND_LITERAL_EXPR)
- return 2;
-
- /* Walk all other expressions. */
- return -1;
}
/* Hook used by staticp to handle language-specific tree codes. */
-int
+tree
c_staticp (tree exp)
{
- if (TREE_CODE (exp) == COMPOUND_LITERAL_EXPR
- && TREE_STATIC (COMPOUND_LITERAL_EXPR_DECL (exp)))
- return 1;
- return 0;
+ return (TREE_CODE (exp) == COMPOUND_LITERAL_EXPR
+ && TREE_STATIC (COMPOUND_LITERAL_EXPR_DECL (exp))
+ ? exp : NULL);
}
@@ -4228,25 +4023,27 @@ boolean_increment (enum tree_code code, tree arg)
switch (code)
{
case PREINCREMENT_EXPR:
- val = build (MODIFY_EXPR, TREE_TYPE (arg), arg, true_res);
+ val = build2 (MODIFY_EXPR, TREE_TYPE (arg), arg, true_res);
break;
case POSTINCREMENT_EXPR:
- val = build (MODIFY_EXPR, TREE_TYPE (arg), arg, true_res);
+ val = build2 (MODIFY_EXPR, TREE_TYPE (arg), arg, true_res);
arg = save_expr (arg);
- val = build (COMPOUND_EXPR, TREE_TYPE (arg), val, arg);
- val = build (COMPOUND_EXPR, TREE_TYPE (arg), arg, val);
+ val = build2 (COMPOUND_EXPR, TREE_TYPE (arg), val, arg);
+ val = build2 (COMPOUND_EXPR, TREE_TYPE (arg), arg, val);
break;
case PREDECREMENT_EXPR:
- val = build (MODIFY_EXPR, TREE_TYPE (arg), arg, invert_truthvalue (arg));
+ val = build2 (MODIFY_EXPR, TREE_TYPE (arg), arg,
+ invert_truthvalue (arg));
break;
case POSTDECREMENT_EXPR:
- val = build (MODIFY_EXPR, TREE_TYPE (arg), arg, invert_truthvalue (arg));
+ val = build2 (MODIFY_EXPR, TREE_TYPE (arg), arg,
+ invert_truthvalue (arg));
arg = save_expr (arg);
- val = build (COMPOUND_EXPR, TREE_TYPE (arg), val, arg);
- val = build (COMPOUND_EXPR, TREE_TYPE (arg), arg, val);
+ val = build2 (COMPOUND_EXPR, TREE_TYPE (arg), val, arg);
+ val = build2 (COMPOUND_EXPR, TREE_TYPE (arg), arg, val);
break;
default:
- abort ();
+ gcc_unreachable ();
}
TREE_SIDE_EFFECTS (val) = 1;
return val;
@@ -4261,16 +4058,18 @@ c_stddef_cpp_builtins(void)
builtin_define_with_value ("__PTRDIFF_TYPE__", PTRDIFF_TYPE, 0);
builtin_define_with_value ("__WCHAR_TYPE__", MODIFIED_WCHAR_TYPE, 0);
builtin_define_with_value ("__WINT_TYPE__", WINT_TYPE, 0);
+ builtin_define_with_value ("__INTMAX_TYPE__", INTMAX_TYPE, 0);
+ builtin_define_with_value ("__UINTMAX_TYPE__", UINTMAX_TYPE, 0);
}
static void
c_init_attributes (void)
{
/* Fill in the built_in_attributes array. */
-#define DEF_ATTR_NULL_TREE(ENUM) \
+#define DEF_ATTR_NULL_TREE(ENUM) \
built_in_attributes[(int) ENUM] = NULL_TREE;
-#define DEF_ATTR_INT(ENUM, VALUE) \
- built_in_attributes[(int) ENUM] = build_int_2 (VALUE, VALUE < 0 ? -1 : 0);
+#define DEF_ATTR_INT(ENUM, VALUE) \
+ built_in_attributes[(int) ENUM] = build_int_cst (NULL_TREE, VALUE);
#define DEF_ATTR_IDENT(ENUM, STRING) \
built_in_attributes[(int) ENUM] = get_identifier (STRING);
#define DEF_ATTR_TREE_LIST(ENUM, PURPOSE, VALUE, CHAIN) \
@@ -4291,39 +4090,31 @@ c_init_attributes (void)
struct attribute_spec.handler. */
static tree
-handle_packed_attribute (tree *node, tree name, tree args ATTRIBUTE_UNUSED,
+handle_packed_attribute (tree *node, tree name, tree ARG_UNUSED (args),
int flags, bool *no_add_attrs)
{
if (TYPE_P (*node))
{
if (!(flags & (int) ATTR_FLAG_TYPE_IN_PLACE))
- *node = build_type_copy (*node);
+ *node = build_variant_type_copy (*node);
TYPE_PACKED (*node) = 1;
- if (TYPE_MAIN_VARIANT (*node) == *node)
- {
- /* If it is the main variant, then pack the other variants
- too. This happens in,
-
- struct Foo {
- struct Foo const *ptr; // creates a variant w/o packed flag
- } __ attribute__((packed)); // packs it now.
- */
- tree probe;
-
- for (probe = *node; probe; probe = TYPE_NEXT_VARIANT (probe))
- TYPE_PACKED (probe) = 1;
- }
-
}
else if (TREE_CODE (*node) == FIELD_DECL)
- DECL_PACKED (*node) = 1;
+ {
+ if (TYPE_ALIGN (TREE_TYPE (*node)) <= BITS_PER_UNIT)
+ warning (OPT_Wattributes,
+ "%qE attribute ignored for field of type %qT",
+ name, TREE_TYPE (*node));
+ else
+ DECL_PACKED (*node) = 1;
+ }
/* We can't set DECL_PACKED for a VAR_DECL, because the bit is
used for DECL_REGISTER. It wouldn't mean anything anyway.
We can't set DECL_PACKED on the type of a TYPE_DECL, because
that changes what the typedef is typing. */
else
{
- warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
+ warning (OPT_Wattributes, "%qE attribute ignored", name);
*no_add_attrs = true;
}
@@ -4335,14 +4126,14 @@ handle_packed_attribute (tree *node, tree name, tree args ATTRIBUTE_UNUSED,
static tree
handle_nocommon_attribute (tree *node, tree name,
- tree args ATTRIBUTE_UNUSED,
- int flags ATTRIBUTE_UNUSED, bool *no_add_attrs)
+ tree ARG_UNUSED (args),
+ int ARG_UNUSED (flags), bool *no_add_attrs)
{
if (TREE_CODE (*node) == VAR_DECL)
DECL_COMMON (*node) = 0;
else
{
- warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
+ warning (OPT_Wattributes, "%qE attribute ignored", name);
*no_add_attrs = true;
}
@@ -4353,14 +4144,14 @@ handle_nocommon_attribute (tree *node, tree name,
struct attribute_spec.handler. */
static tree
-handle_common_attribute (tree *node, tree name, tree args ATTRIBUTE_UNUSED,
- int flags ATTRIBUTE_UNUSED, bool *no_add_attrs)
+handle_common_attribute (tree *node, tree name, tree ARG_UNUSED (args),
+ int ARG_UNUSED (flags), bool *no_add_attrs)
{
if (TREE_CODE (*node) == VAR_DECL)
DECL_COMMON (*node) = 1;
else
{
- warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
+ warning (OPT_Wattributes, "%qE attribute ignored", name);
*no_add_attrs = true;
}
@@ -4371,8 +4162,8 @@ handle_common_attribute (tree *node, tree name, tree args ATTRIBUTE_UNUSED,
struct attribute_spec.handler. */
static tree
-handle_noreturn_attribute (tree *node, tree name, tree args ATTRIBUTE_UNUSED,
- int flags ATTRIBUTE_UNUSED, bool *no_add_attrs)
+handle_noreturn_attribute (tree *node, tree name, tree ARG_UNUSED (args),
+ int ARG_UNUSED (flags), bool *no_add_attrs)
{
tree type = TREE_TYPE (*node);
@@ -4384,10 +4175,10 @@ handle_noreturn_attribute (tree *node, tree name, tree args ATTRIBUTE_UNUSED,
TREE_TYPE (*node)
= build_pointer_type
(build_type_variant (TREE_TYPE (type),
- TREE_READONLY (TREE_TYPE (type)), 1));
+ TYPE_READONLY (TREE_TYPE (type)), 1));
else
{
- warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
+ warning (OPT_Wattributes, "%qE attribute ignored", name);
*no_add_attrs = true;
}
@@ -4399,14 +4190,14 @@ handle_noreturn_attribute (tree *node, tree name, tree args ATTRIBUTE_UNUSED,
static tree
handle_noinline_attribute (tree *node, tree name,
- tree args ATTRIBUTE_UNUSED,
- int flags ATTRIBUTE_UNUSED, bool *no_add_attrs)
+ tree ARG_UNUSED (args),
+ int ARG_UNUSED (flags), bool *no_add_attrs)
{
if (TREE_CODE (*node) == FUNCTION_DECL)
DECL_UNINLINABLE (*node) = 1;
else
{
- warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
+ warning (OPT_Wattributes, "%qE attribute ignored", name);
*no_add_attrs = true;
}
@@ -4418,8 +4209,8 @@ handle_noinline_attribute (tree *node, tree name,
static tree
handle_always_inline_attribute (tree *node, tree name,
- tree args ATTRIBUTE_UNUSED,
- int flags ATTRIBUTE_UNUSED,
+ tree ARG_UNUSED (args),
+ int ARG_UNUSED (flags),
bool *no_add_attrs)
{
if (TREE_CODE (*node) == FUNCTION_DECL)
@@ -4429,19 +4220,64 @@ handle_always_inline_attribute (tree *node, tree name,
}
else
{
- warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
+ warning (OPT_Wattributes, "%qE attribute ignored", name);
*no_add_attrs = true;
}
return NULL_TREE;
}
+/* Handle a "gnu_inline" attribute; arguments as in
+ struct attribute_spec.handler. */
+
+static tree
+handle_gnu_inline_attribute (tree *node, tree name,
+ tree ARG_UNUSED (args),
+ int ARG_UNUSED (flags),
+ bool *no_add_attrs)
+{
+ if (TREE_CODE (*node) == FUNCTION_DECL && DECL_DECLARED_INLINE_P (*node))
+ {
+ /* Do nothing else, just set the attribute. We'll get at
+ it later with lookup_attribute. */
+ }
+ else
+ {
+ warning (OPT_Wattributes, "%qE attribute ignored", name);
+ *no_add_attrs = true;
+ }
+
+ return NULL_TREE;
+}
+
+/* Handle a "flatten" attribute; arguments as in
+ struct attribute_spec.handler. */
+
+static tree
+handle_flatten_attribute (tree *node, tree name,
+ tree args ATTRIBUTE_UNUSED,
+ int flags ATTRIBUTE_UNUSED, bool *no_add_attrs)
+{
+ if (TREE_CODE (*node) == FUNCTION_DECL)
+ /* Do nothing else, just set the attribute. We'll get at
+ it later with lookup_attribute. */
+ ;
+ else
+ {
+ warning (OPT_Wattributes, "%qE attribute ignored", name);
+ *no_add_attrs = true;
+ }
+
+ return NULL_TREE;
+}
+
+
/* Handle a "used" attribute; arguments as in
struct attribute_spec.handler. */
static tree
-handle_used_attribute (tree *pnode, tree name, tree args ATTRIBUTE_UNUSED,
- int flags ATTRIBUTE_UNUSED, bool *no_add_attrs)
+handle_used_attribute (tree *pnode, tree name, tree ARG_UNUSED (args),
+ int ARG_UNUSED (flags), bool *no_add_attrs)
{
tree node = *pnode;
@@ -4449,10 +4285,11 @@ handle_used_attribute (tree *pnode, tree name, tree args ATTRIBUTE_UNUSED,
|| (TREE_CODE (node) == VAR_DECL && TREE_STATIC (node)))
{
TREE_USED (node) = 1;
+ DECL_PRESERVE_P (node) = 1;
}
else
{
- warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
+ warning (OPT_Wattributes, "%qE attribute ignored", name);
*no_add_attrs = true;
}
@@ -4463,8 +4300,8 @@ handle_used_attribute (tree *pnode, tree name, tree args ATTRIBUTE_UNUSED,
struct attribute_spec.handler. */
static tree
-handle_unused_attribute (tree *node, tree name, tree args ATTRIBUTE_UNUSED,
- int flags ATTRIBUTE_UNUSED, bool *no_add_attrs)
+handle_unused_attribute (tree *node, tree name, tree ARG_UNUSED (args),
+ int flags, bool *no_add_attrs)
{
if (DECL_P (*node))
{
@@ -4478,26 +4315,56 @@ handle_unused_attribute (tree *node, tree name, tree args ATTRIBUTE_UNUSED,
TREE_USED (decl) = 1;
else
{
- warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
+ warning (OPT_Wattributes, "%qE attribute ignored", name);
*no_add_attrs = true;
}
}
else
{
if (!(flags & (int) ATTR_FLAG_TYPE_IN_PLACE))
- *node = build_type_copy (*node);
+ *node = build_variant_type_copy (*node);
TREE_USED (*node) = 1;
}
return NULL_TREE;
}
+/* Handle a "externally_visible" attribute; arguments as in
+ struct attribute_spec.handler. */
+
+static tree
+handle_externally_visible_attribute (tree *pnode, tree name,
+ tree ARG_UNUSED (args),
+ int ARG_UNUSED (flags),
+ bool *no_add_attrs)
+{
+ tree node = *pnode;
+
+ if (TREE_CODE (node) == FUNCTION_DECL || TREE_CODE (node) == VAR_DECL)
+ {
+ if ((!TREE_STATIC (node) && TREE_CODE (node) != FUNCTION_DECL
+ && !DECL_EXTERNAL (node)) || !TREE_PUBLIC (node))
+ {
+ warning (OPT_Wattributes,
+ "%qE attribute have effect only on public objects", name);
+ *no_add_attrs = true;
+ }
+ }
+ else
+ {
+ warning (OPT_Wattributes, "%qE attribute ignored", name);
+ *no_add_attrs = true;
+ }
+
+ return NULL_TREE;
+}
+
/* Handle a "const" attribute; arguments as in
struct attribute_spec.handler. */
static tree
-handle_const_attribute (tree *node, tree name, tree args ATTRIBUTE_UNUSED,
- int flags ATTRIBUTE_UNUSED, bool *no_add_attrs)
+handle_const_attribute (tree *node, tree name, tree ARG_UNUSED (args),
+ int ARG_UNUSED (flags), bool *no_add_attrs)
{
tree type = TREE_TYPE (*node);
@@ -4512,7 +4379,7 @@ handle_const_attribute (tree *node, tree name, tree args ATTRIBUTE_UNUSED,
TREE_THIS_VOLATILE (TREE_TYPE (type))));
else
{
- warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
+ warning (OPT_Wattributes, "%qE attribute ignored", name);
*no_add_attrs = true;
}
@@ -4524,42 +4391,46 @@ handle_const_attribute (tree *node, tree name, tree args ATTRIBUTE_UNUSED,
static tree
handle_transparent_union_attribute (tree *node, tree name,
- tree args ATTRIBUTE_UNUSED, int flags,
+ tree ARG_UNUSED (args), int flags,
bool *no_add_attrs)
{
- tree decl = NULL_TREE;
- tree *type = NULL;
- int is_type = 0;
+ tree type = NULL;
+
+ *no_add_attrs = true;
if (DECL_P (*node))
{
- decl = *node;
- type = &TREE_TYPE (decl);
- is_type = TREE_CODE (*node) == TYPE_DECL;
+ if (TREE_CODE (*node) != TYPE_DECL)
+ goto ignored;
+ node = &TREE_TYPE (*node);
+ type = *node;
}
else if (TYPE_P (*node))
- type = node, is_type = 1;
+ type = *node;
+ else
+ goto ignored;
- if (is_type
- && TREE_CODE (*type) == UNION_TYPE
- && (decl == 0
- || (TYPE_FIELDS (*type) != 0
- && TYPE_MODE (*type) == DECL_MODE (TYPE_FIELDS (*type)))))
+ if (TREE_CODE (type) == UNION_TYPE)
{
+ /* When IN_PLACE is set, leave the check for FIELDS and MODE to
+ the code in finish_struct. */
if (!(flags & (int) ATTR_FLAG_TYPE_IN_PLACE))
- *type = build_type_copy (*type);
- TYPE_TRANSPARENT_UNION (*type) = 1;
- }
- else if (decl != 0 && TREE_CODE (decl) == PARM_DECL
- && TREE_CODE (*type) == UNION_TYPE
- && TYPE_MODE (*type) == DECL_MODE (TYPE_FIELDS (*type)))
- DECL_TRANSPARENT_UNION (decl) = 1;
- else
- {
- warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
- *no_add_attrs = true;
+ {
+ if (TYPE_FIELDS (type) == NULL_TREE
+ || TYPE_MODE (type) != DECL_MODE (TYPE_FIELDS (type)))
+ goto ignored;
+
+ /* A type variant isn't good enough, since we don't a cast
+ to such a type removed as a no-op. */
+ *node = type = build_duplicate_type (type);
+ }
+
+ TYPE_TRANSPARENT_UNION (type) = 1;
+ return NULL_TREE;
}
+ ignored:
+ warning (OPT_Wattributes, "%qE attribute ignored", name);
return NULL_TREE;
}
@@ -4568,8 +4439,8 @@ handle_transparent_union_attribute (tree *node, tree name,
static tree
handle_constructor_attribute (tree *node, tree name,
- tree args ATTRIBUTE_UNUSED,
- int flags ATTRIBUTE_UNUSED,
+ tree ARG_UNUSED (args),
+ int ARG_UNUSED (flags),
bool *no_add_attrs)
{
tree decl = *node;
@@ -4584,7 +4455,7 @@ handle_constructor_attribute (tree *node, tree name,
}
else
{
- warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
+ warning (OPT_Wattributes, "%qE attribute ignored", name);
*no_add_attrs = true;
}
@@ -4596,8 +4467,8 @@ handle_constructor_attribute (tree *node, tree name,
static tree
handle_destructor_attribute (tree *node, tree name,
- tree args ATTRIBUTE_UNUSED,
- int flags ATTRIBUTE_UNUSED,
+ tree ARG_UNUSED (args),
+ int ARG_UNUSED (flags),
bool *no_add_attrs)
{
tree decl = *node;
@@ -4612,7 +4483,7 @@ handle_destructor_attribute (tree *node, tree name,
}
else
{
- warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
+ warning (OPT_Wattributes, "%qE attribute ignored", name);
*no_add_attrs = true;
}
@@ -4623,15 +4494,15 @@ handle_destructor_attribute (tree *node, tree name,
struct attribute_spec.handler. */
static tree
-handle_mode_attribute (tree *node, tree name, tree args ATTRIBUTE_UNUSED,
- int flags ATTRIBUTE_UNUSED, bool *no_add_attrs)
+handle_mode_attribute (tree *node, tree name, tree args,
+ int ARG_UNUSED (flags), bool *no_add_attrs)
{
tree type = *node;
*no_add_attrs = true;
if (TREE_CODE (TREE_VALUE (args)) != IDENTIFIER_NODE)
- warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
+ warning (OPT_Wattributes, "%qE attribute ignored", name);
else
{
int j;
@@ -4639,12 +4510,12 @@ handle_mode_attribute (tree *node, tree name, tree args ATTRIBUTE_UNUSED,
int len = strlen (p);
enum machine_mode mode = VOIDmode;
tree typefm;
- tree ptr_type;
+ bool valid_mode;
if (len > 4 && p[0] == '_' && p[1] == '_'
&& p[len - 1] == '_' && p[len - 2] == '_')
{
- char *newp = alloca (len - 1);
+ char *newp = (char *) alloca (len - 1);
strcpy (newp, &p[2]);
newp[len - 4] = '\0';
@@ -4653,11 +4524,11 @@ handle_mode_attribute (tree *node, tree name, tree args ATTRIBUTE_UNUSED,
/* Change this type to have a type with the specified mode.
First check for the special modes. */
- if (! strcmp (p, "byte"))
+ if (!strcmp (p, "byte"))
mode = byte_mode;
else if (!strcmp (p, "word"))
mode = word_mode;
- else if (! strcmp (p, "pointer"))
+ else if (!strcmp (p, "pointer"))
mode = ptr_mode;
else
for (j = 0; j < NUM_MACHINE_MODES; j++)
@@ -4668,76 +4539,107 @@ handle_mode_attribute (tree *node, tree name, tree args ATTRIBUTE_UNUSED,
}
if (mode == VOIDmode)
- error ("unknown machine mode `%s'", p);
- else if (0 == (typefm = (*lang_hooks.types.type_for_mode)
- (mode, TREE_UNSIGNED (type))))
- error ("no data type for mode `%s'", p);
- else if ((TREE_CODE (type) == POINTER_TYPE
- || TREE_CODE (type) == REFERENCE_TYPE)
- && !(*targetm.valid_pointer_mode) (mode))
- error ("invalid pointer mode `%s'", p);
- else
{
- /* If this is a vector, make sure we either have hardware
- support, or we can emulate it. */
- if (VECTOR_MODE_P (mode) && !vector_mode_valid_p (mode))
+ error ("unknown machine mode %qs", p);
+ return NULL_TREE;
+ }
+
+ valid_mode = false;
+ switch (GET_MODE_CLASS (mode))
+ {
+ case MODE_INT:
+ case MODE_PARTIAL_INT:
+ case MODE_FLOAT:
+ case MODE_DECIMAL_FLOAT:
+ valid_mode = targetm.scalar_mode_supported_p (mode);
+ break;
+
+ case MODE_COMPLEX_INT:
+ case MODE_COMPLEX_FLOAT:
+ valid_mode = targetm.scalar_mode_supported_p (GET_MODE_INNER (mode));
+ break;
+
+ case MODE_VECTOR_INT:
+ case MODE_VECTOR_FLOAT:
+ warning (OPT_Wattributes, "specifying vector types with "
+ "__attribute__ ((mode)) is deprecated");
+ warning (OPT_Wattributes,
+ "use __attribute__ ((vector_size)) instead");
+ valid_mode = vector_mode_valid_p (mode);
+ break;
+
+ default:
+ break;
+ }
+ if (!valid_mode)
+ {
+ error ("unable to emulate %qs", p);
+ return NULL_TREE;
+ }
+
+ if (POINTER_TYPE_P (type))
+ {
+ tree (*fn)(tree, enum machine_mode, bool);
+
+ if (!targetm.valid_pointer_mode (mode))
{
- error ("unable to emulate '%s'", GET_MODE_NAME (mode));
+ error ("invalid pointer mode %qs", p);
return NULL_TREE;
}
if (TREE_CODE (type) == POINTER_TYPE)
+ fn = build_pointer_type_for_mode;
+ else
+ fn = build_reference_type_for_mode;
+ typefm = fn (TREE_TYPE (type), mode, false);
+ }
+ else
+ typefm = lang_hooks.types.type_for_mode (mode, TYPE_UNSIGNED (type));
+
+ if (typefm == NULL_TREE)
+ {
+ error ("no data type for mode %qs", p);
+ return NULL_TREE;
+ }
+ else if (TREE_CODE (type) == ENUMERAL_TYPE)
+ {
+ /* For enumeral types, copy the precision from the integer
+ type returned above. If not an INTEGER_TYPE, we can't use
+ this mode for this type. */
+ if (TREE_CODE (typefm) != INTEGER_TYPE)
{
- ptr_type = build_pointer_type_for_mode (TREE_TYPE (type),
- mode);
- *node = ptr_type;
- }
- else if (TREE_CODE (type) == REFERENCE_TYPE)
- {
- ptr_type = build_reference_type_for_mode (TREE_TYPE (type),
- mode);
- *node = ptr_type;
+ error ("cannot use mode %qs for enumeral types", p);
+ return NULL_TREE;
}
- else if (TREE_CODE (type) == ENUMERAL_TYPE)
- {
- /* For enumeral types, copy the precision from the integer
- type returned above. If not an INTEGER_TYPE, we can't use
- this mode for this type. */
- if (TREE_CODE (typefm) != INTEGER_TYPE)
- {
- error ("cannot use mode %qs for enumeral types", p);
- return NULL_TREE;
- }
- if (!(flags & (int) ATTR_FLAG_TYPE_IN_PLACE))
- type = build_type_copy (type);
-
- /* We cannot use layout_type here, because that will attempt
- to re-layout all variants, corrupting our original. */
+ if (flags & ATTR_FLAG_TYPE_IN_PLACE)
+ {
TYPE_PRECISION (type) = TYPE_PRECISION (typefm);
- TYPE_MIN_VALUE (type) = TYPE_MIN_VALUE (typefm);
- TYPE_MAX_VALUE (type) = TYPE_MAX_VALUE (typefm);
- TYPE_SIZE (type) = TYPE_SIZE (typefm);
- TYPE_SIZE_UNIT (type) = TYPE_SIZE_UNIT (typefm);
- TYPE_MODE (type) = TYPE_MODE (typefm);
- if (!TYPE_USER_ALIGN (type))
- TYPE_ALIGN (type) = TYPE_ALIGN (typefm);
-
- *node = type;
+ typefm = type;
}
- else if (VECTOR_MODE_P (mode)
- ? TREE_CODE (type) != TREE_CODE (TREE_TYPE (typefm))
- : TREE_CODE (type) != TREE_CODE (typefm))
-
+ else
{
- error ("mode `%s' applied to inappropriate type", p);
- return NULL_TREE;
+ /* We cannot build a type variant, as there's code that assumes
+ that TYPE_MAIN_VARIANT has the same mode. This includes the
+ debug generators. Instead, create a subrange type. This
+ results in all of the enumeral values being emitted only once
+ in the original, and the subtype gets them by reference. */
+ if (TYPE_UNSIGNED (type))
+ typefm = make_unsigned_type (TYPE_PRECISION (typefm));
+ else
+ typefm = make_signed_type (TYPE_PRECISION (typefm));
+ TREE_TYPE (typefm) = type;
}
- else
- *node = typefm;
-
- /* No need to layout the type here. The caller should do this. */
}
+ else if (VECTOR_MODE_P (mode)
+ ? TREE_CODE (type) != TREE_CODE (TREE_TYPE (typefm))
+ : TREE_CODE (type) != TREE_CODE (typefm))
+ {
+ error ("mode %qs applied to inappropriate type", p);
+ return NULL_TREE;
+ }
+
+ *node = typefm;
}
return NULL_TREE;
@@ -4747,23 +4649,25 @@ handle_mode_attribute (tree *node, tree name, tree args ATTRIBUTE_UNUSED,
struct attribute_spec.handler. */
static tree
-handle_section_attribute (tree *node, tree name ATTRIBUTE_UNUSED, tree args,
- int flags ATTRIBUTE_UNUSED, bool *no_add_attrs)
+handle_section_attribute (tree *node, tree ARG_UNUSED (name), tree args,
+ int ARG_UNUSED (flags), bool *no_add_attrs)
{
tree decl = *node;
if (targetm.have_named_sections)
{
+ user_defined_section_attribute = true;
+
if ((TREE_CODE (decl) == FUNCTION_DECL
|| TREE_CODE (decl) == VAR_DECL)
&& TREE_CODE (TREE_VALUE (args)) == STRING_CST)
{
if (TREE_CODE (decl) == VAR_DECL
&& current_function_decl != NULL_TREE
- && ! TREE_STATIC (decl))
+ && !TREE_STATIC (decl))
{
error ("%Jsection attribute cannot be specified for "
- "local variables", decl);
+ "local variables", decl);
*no_add_attrs = true;
}
@@ -4773,8 +4677,8 @@ handle_section_attribute (tree *node, tree name ATTRIBUTE_UNUSED, tree args,
&& strcmp (TREE_STRING_POINTER (DECL_SECTION_NAME (decl)),
TREE_STRING_POINTER (TREE_VALUE (args))) != 0)
{
- error ("%Jsection of '%D' conflicts with previous declaration",
- *node, *node);
+ error ("section of %q+D conflicts with previous declaration",
+ *node);
*no_add_attrs = true;
}
else
@@ -4782,7 +4686,7 @@ handle_section_attribute (tree *node, tree name ATTRIBUTE_UNUSED, tree args,
}
else
{
- error ("%Jsection attribute not allowed for '%D'", *node, *node);
+ error ("section attribute not allowed for %q+D", *node);
*no_add_attrs = true;
}
}
@@ -4799,7 +4703,7 @@ handle_section_attribute (tree *node, tree name ATTRIBUTE_UNUSED, tree args,
struct attribute_spec.handler. */
static tree
-handle_aligned_attribute (tree *node, tree name ATTRIBUTE_UNUSED, tree args,
+handle_aligned_attribute (tree *node, tree ARG_UNUSED (name), tree args,
int flags, bool *no_add_attrs)
{
tree decl = NULL_TREE;
@@ -4818,12 +4722,6 @@ handle_aligned_attribute (tree *node, tree name ATTRIBUTE_UNUSED, tree args,
else if (TYPE_P (*node))
type = node, is_type = 1;
- /* Strip any NOPs of any kind. */
- while (TREE_CODE (align_expr) == NOP_EXPR
- || TREE_CODE (align_expr) == CONVERT_EXPR
- || TREE_CODE (align_expr) == NON_LVALUE_EXPR)
- align_expr = TREE_OPERAND (align_expr, 0);
-
if (TREE_CODE (align_expr) != INTEGER_CST)
{
error ("requested alignment is not a constant");
@@ -4847,14 +4745,14 @@ handle_aligned_attribute (tree *node, tree name ATTRIBUTE_UNUSED, tree args,
&& DECL_ORIGINAL_TYPE (decl) == NULL_TREE)
{
tree tt = TREE_TYPE (decl);
- *type = build_type_copy (*type);
+ *type = build_variant_type_copy (*type);
DECL_ORIGINAL_TYPE (decl) = tt;
TYPE_NAME (*type) = decl;
TREE_USED (*type) = TREE_USED (decl);
TREE_TYPE (decl) = *type;
}
else if (!(flags & (int) ATTR_FLAG_TYPE_IN_PLACE))
- *type = build_type_copy (*type);
+ *type = build_variant_type_copy (*type);
TYPE_ALIGN (*type) = (1 << i) * BITS_PER_UNIT;
TYPE_USER_ALIGN (*type) = 1;
@@ -4862,7 +4760,7 @@ handle_aligned_attribute (tree *node, tree name ATTRIBUTE_UNUSED, tree args,
else if (TREE_CODE (decl) != VAR_DECL
&& TREE_CODE (decl) != FIELD_DECL)
{
- error ("%Jalignment may not be specified for '%D'", decl, decl);
+ error ("alignment may not be specified for %q+D", decl);
*no_add_attrs = true;
}
else
@@ -4878,12 +4776,17 @@ handle_aligned_attribute (tree *node, tree name ATTRIBUTE_UNUSED, tree args,
struct attribute_spec.handler. */
static tree
-handle_weak_attribute (tree *node, tree name ATTRIBUTE_UNUSED,
- tree args ATTRIBUTE_UNUSED,
- int flags ATTRIBUTE_UNUSED,
- bool *no_add_attrs ATTRIBUTE_UNUSED)
+handle_weak_attribute (tree *node, tree name,
+ tree ARG_UNUSED (args),
+ int ARG_UNUSED (flags),
+ bool * ARG_UNUSED (no_add_attrs))
{
- declare_weak (*node);
+ if (TREE_CODE (*node) == FUNCTION_DECL
+ || TREE_CODE (*node) == VAR_DECL)
+ declare_weak (*node);
+ else
+ warning (OPT_Wattributes, "%qE attribute ignored", name);
+
return NULL_TREE;
}
@@ -4893,24 +4796,35 @@ handle_weak_attribute (tree *node, tree name ATTRIBUTE_UNUSED,
static tree
handle_alias_attribute (tree *node, tree name, tree args,
- int flags ATTRIBUTE_UNUSED, bool *no_add_attrs)
+ int ARG_UNUSED (flags), bool *no_add_attrs)
{
tree decl = *node;
if ((TREE_CODE (decl) == FUNCTION_DECL && DECL_INITIAL (decl))
- || (TREE_CODE (decl) != FUNCTION_DECL && ! DECL_EXTERNAL (decl)))
- {
- error ("%J'%D' defined both normally and as an alias", decl, decl);
+ || (TREE_CODE (decl) != FUNCTION_DECL
+ && TREE_PUBLIC (decl) && !DECL_EXTERNAL (decl))
+ /* A static variable declaration is always a tentative definition,
+ but the alias is a non-tentative definition which overrides. */
+ || (TREE_CODE (decl) != FUNCTION_DECL
+ && ! TREE_PUBLIC (decl) && DECL_INITIAL (decl)))
+ {
+ error ("%q+D defined both normally and as an alias", decl);
*no_add_attrs = true;
}
- else if (decl_function_context (decl) == 0)
+
+ /* Note that the very first time we process a nested declaration,
+ decl_function_context will not be set. Indeed, *would* never
+ be set except for the DECL_INITIAL/DECL_EXTERNAL frobbery that
+ we do below. After such frobbery, pushdecl would set the context.
+ In any case, this is never what we want. */
+ else if (decl_function_context (decl) == 0 && current_function_decl == NULL)
{
tree id;
id = TREE_VALUE (args);
if (TREE_CODE (id) != STRING_CST)
{
- error ("alias arg not a string");
+ error ("alias argument not a string");
*no_add_attrs = true;
return NULL_TREE;
}
@@ -4921,12 +4835,65 @@ handle_alias_attribute (tree *node, tree name, tree args,
if (TREE_CODE (decl) == FUNCTION_DECL)
DECL_INITIAL (decl) = error_mark_node;
else
- DECL_EXTERNAL (decl) = 0;
+ {
+ if (lookup_attribute ("weakref", DECL_ATTRIBUTES (decl)))
+ DECL_EXTERNAL (decl) = 1;
+ else
+ DECL_EXTERNAL (decl) = 0;
+ TREE_STATIC (decl) = 1;
+ }
}
else
{
- warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
+ warning (OPT_Wattributes, "%qE attribute ignored", name);
+ *no_add_attrs = true;
+ }
+
+ return NULL_TREE;
+}
+
+/* Handle a "weakref" attribute; arguments as in struct
+ attribute_spec.handler. */
+
+static tree
+handle_weakref_attribute (tree *node, tree ARG_UNUSED (name), tree args,
+ int flags, bool *no_add_attrs)
+{
+ tree attr = NULL_TREE;
+
+ /* We must ignore the attribute when it is associated with
+ local-scoped decls, since attribute alias is ignored and many
+ such symbols do not even have a DECL_WEAK field. */
+ if (decl_function_context (*node) || current_function_decl)
+ {
+ warning (OPT_Wattributes, "%qE attribute ignored", name);
+ *no_add_attrs = true;
+ return NULL_TREE;
+ }
+
+ /* The idea here is that `weakref("name")' mutates into `weakref,
+ alias("name")', and weakref without arguments, in turn,
+ implicitly adds weak. */
+
+ if (args)
+ {
+ attr = tree_cons (get_identifier ("alias"), args, attr);
+ attr = tree_cons (get_identifier ("weakref"), NULL_TREE, attr);
+
*no_add_attrs = true;
+
+ decl_attributes (node, attr, flags);
+ }
+ else
+ {
+ if (lookup_attribute ("alias", DECL_ATTRIBUTES (*node)))
+ error ("%Jweakref attribute must appear before alias attribute",
+ *node);
+
+ /* Can't call declare_weak because it wants this to be TREE_PUBLIC,
+ and that isn't supported; and because it wants to add it to
+ the list of weak decls, which isn't helpful. */
+ DECL_WEAK (*node) = 1;
}
return NULL_TREE;
@@ -4937,76 +4904,169 @@ handle_alias_attribute (tree *node, tree name, tree args,
static tree
handle_visibility_attribute (tree *node, tree name, tree args,
- int flags ATTRIBUTE_UNUSED,
- bool *no_add_attrs)
+ int ARG_UNUSED (flags),
+ bool *ARG_UNUSED (no_add_attrs))
{
tree decl = *node;
tree id = TREE_VALUE (args);
+ enum symbol_visibility vis;
- *no_add_attrs = true;
-
- if (decl_function_context (decl) != 0 || ! TREE_PUBLIC (decl))
+ if (TYPE_P (*node))
+ {
+ if (TREE_CODE (*node) == ENUMERAL_TYPE)
+ /* OK */;
+ else if (TREE_CODE (*node) != RECORD_TYPE && TREE_CODE (*node) != UNION_TYPE)
+ {
+ warning (OPT_Wattributes, "%qE attribute ignored on non-class types",
+ name);
+ return NULL_TREE;
+ }
+ else if (TYPE_FIELDS (*node))
+ {
+ error ("%qE attribute ignored because %qT is already defined",
+ name, *node);
+ return NULL_TREE;
+ }
+ }
+ else if (decl_function_context (decl) != 0 || !TREE_PUBLIC (decl))
{
- warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
+ warning (OPT_Wattributes, "%qE attribute ignored", name);
return NULL_TREE;
}
if (TREE_CODE (id) != STRING_CST)
{
- error ("visibility arg not a string");
+ error ("visibility argument not a string");
return NULL_TREE;
}
+ /* If this is a type, set the visibility on the type decl. */
+ if (TYPE_P (decl))
+ {
+ decl = TYPE_NAME (decl);
+ if (!decl)
+ return NULL_TREE;
+ if (TREE_CODE (decl) == IDENTIFIER_NODE)
+ {
+ warning (OPT_Wattributes, "%qE attribute ignored on types",
+ name);
+ return NULL_TREE;
+ }
+ }
+
if (strcmp (TREE_STRING_POINTER (id), "default") == 0)
- DECL_VISIBILITY (decl) = VISIBILITY_DEFAULT;
+ vis = VISIBILITY_DEFAULT;
else if (strcmp (TREE_STRING_POINTER (id), "internal") == 0)
- DECL_VISIBILITY (decl) = VISIBILITY_INTERNAL;
+ vis = VISIBILITY_INTERNAL;
else if (strcmp (TREE_STRING_POINTER (id), "hidden") == 0)
- DECL_VISIBILITY (decl) = VISIBILITY_HIDDEN;
+ vis = VISIBILITY_HIDDEN;
else if (strcmp (TREE_STRING_POINTER (id), "protected") == 0)
- DECL_VISIBILITY (decl) = VISIBILITY_PROTECTED;
+ vis = VISIBILITY_PROTECTED;
else
- error ("visibility arg must be one of \"default\", \"hidden\", \"protected\" or \"internal\"");
+ {
+ error ("visibility argument must be one of \"default\", \"hidden\", \"protected\" or \"internal\"");
+ vis = VISIBILITY_DEFAULT;
+ }
+
+ if (DECL_VISIBILITY_SPECIFIED (decl)
+ && vis != DECL_VISIBILITY (decl)
+ && lookup_attribute ("visibility", (TYPE_P (*node)
+ ? TYPE_ATTRIBUTES (*node)
+ : DECL_ATTRIBUTES (decl))))
+ error ("%qD redeclared with different visibility", decl);
+
+ DECL_VISIBILITY (decl) = vis;
+ DECL_VISIBILITY_SPECIFIED (decl) = 1;
+
+ /* Go ahead and attach the attribute to the node as well. This is needed
+ so we can determine whether we have VISIBILITY_DEFAULT because the
+ visibility was not specified, or because it was explicitly overridden
+ from the containing scope. */
return NULL_TREE;
}
+/* Determine the ELF symbol visibility for DECL, which is either a
+ variable or a function. It is an error to use this function if a
+ definition of DECL is not available in this translation unit.
+ Returns true if the final visibility has been determined by this
+ function; false if the caller is free to make additional
+ modifications. */
+
+bool
+c_determine_visibility (tree decl)
+{
+ gcc_assert (TREE_CODE (decl) == VAR_DECL
+ || TREE_CODE (decl) == FUNCTION_DECL);
+
+ /* If the user explicitly specified the visibility with an
+ attribute, honor that. DECL_VISIBILITY will have been set during
+ the processing of the attribute. We check for an explicit
+ attribute, rather than just checking DECL_VISIBILITY_SPECIFIED,
+ to distinguish the use of an attribute from the use of a "#pragma
+ GCC visibility push(...)"; in the latter case we still want other
+ considerations to be able to overrule the #pragma. */
+ if (lookup_attribute ("visibility", DECL_ATTRIBUTES (decl)))
+ return true;
+
+ /* Anything that is exported must have default visibility. */
+ if (TARGET_DLLIMPORT_DECL_ATTRIBUTES
+ && lookup_attribute ("dllexport", DECL_ATTRIBUTES (decl)))
+ {
+ DECL_VISIBILITY (decl) = VISIBILITY_DEFAULT;
+ DECL_VISIBILITY_SPECIFIED (decl) = 1;
+ return true;
+ }
+
+ /* Set default visibility to whatever the user supplied with
+ visibility_specified depending on #pragma GCC visibility. */
+ if (!DECL_VISIBILITY_SPECIFIED (decl))
+ {
+ DECL_VISIBILITY (decl) = default_visibility;
+ DECL_VISIBILITY_SPECIFIED (decl) = visibility_options.inpragma;
+ }
+ return false;
+}
+
/* Handle an "tls_model" attribute; arguments as in
struct attribute_spec.handler. */
static tree
handle_tls_model_attribute (tree *node, tree name, tree args,
- int flags ATTRIBUTE_UNUSED, bool *no_add_attrs)
+ int ARG_UNUSED (flags), bool *no_add_attrs)
{
+ tree id;
tree decl = *node;
+ enum tls_model kind;
- if (! DECL_THREAD_LOCAL (decl))
+ *no_add_attrs = true;
+
+ if (!DECL_THREAD_LOCAL_P (decl))
{
- warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
- *no_add_attrs = true;
+ warning (OPT_Wattributes, "%qE attribute ignored", name);
+ return NULL_TREE;
}
- else
- {
- tree id;
- id = TREE_VALUE (args);
- if (TREE_CODE (id) != STRING_CST)
- {
- error ("tls_model arg not a string");
- *no_add_attrs = true;
- return NULL_TREE;
- }
- if (strcmp (TREE_STRING_POINTER (id), "local-exec")
- && strcmp (TREE_STRING_POINTER (id), "initial-exec")
- && strcmp (TREE_STRING_POINTER (id), "local-dynamic")
- && strcmp (TREE_STRING_POINTER (id), "global-dynamic"))
- {
- error ("tls_model arg must be one of \"local-exec\", \"initial-exec\", \"local-dynamic\" or \"global-dynamic\"");
- *no_add_attrs = true;
- return NULL_TREE;
- }
+ kind = DECL_TLS_MODEL (decl);
+ id = TREE_VALUE (args);
+ if (TREE_CODE (id) != STRING_CST)
+ {
+ error ("tls_model argument not a string");
+ return NULL_TREE;
}
+ if (!strcmp (TREE_STRING_POINTER (id), "local-exec"))
+ kind = TLS_MODEL_LOCAL_EXEC;
+ else if (!strcmp (TREE_STRING_POINTER (id), "initial-exec"))
+ kind = TLS_MODEL_INITIAL_EXEC;
+ else if (!strcmp (TREE_STRING_POINTER (id), "local-dynamic"))
+ kind = optimize ? TLS_MODEL_LOCAL_DYNAMIC : TLS_MODEL_GLOBAL_DYNAMIC;
+ else if (!strcmp (TREE_STRING_POINTER (id), "global-dynamic"))
+ kind = TLS_MODEL_GLOBAL_DYNAMIC;
+ else
+ error ("tls_model argument must be one of \"local-exec\", \"initial-exec\", \"local-dynamic\" or \"global-dynamic\"");
+
+ DECL_TLS_MODEL (decl) = kind;
return NULL_TREE;
}
@@ -5015,20 +5075,20 @@ handle_tls_model_attribute (tree *node, tree name, tree args,
static tree
handle_no_instrument_function_attribute (tree *node, tree name,
- tree args ATTRIBUTE_UNUSED,
- int flags ATTRIBUTE_UNUSED,
+ tree ARG_UNUSED (args),
+ int ARG_UNUSED (flags),
bool *no_add_attrs)
{
tree decl = *node;
if (TREE_CODE (decl) != FUNCTION_DECL)
{
- error ("%J'%E' attribute applies only to functions", decl, name);
+ error ("%J%qE attribute applies only to functions", decl, name);
*no_add_attrs = true;
}
else if (DECL_INITIAL (decl))
{
- error ("%Jcan't set '%E' attribute after definition", decl, name);
+ error ("%Jcan%'t set %qE attribute after definition", decl, name);
*no_add_attrs = true;
}
else
@@ -5041,15 +5101,33 @@ handle_no_instrument_function_attribute (tree *node, tree name,
struct attribute_spec.handler. */
static tree
-handle_malloc_attribute (tree *node, tree name, tree args ATTRIBUTE_UNUSED,
- int flags ATTRIBUTE_UNUSED, bool *no_add_attrs)
+handle_malloc_attribute (tree *node, tree name, tree ARG_UNUSED (args),
+ int ARG_UNUSED (flags), bool *no_add_attrs)
{
- if (TREE_CODE (*node) == FUNCTION_DECL)
+ if (TREE_CODE (*node) == FUNCTION_DECL
+ && POINTER_TYPE_P (TREE_TYPE (TREE_TYPE (*node))))
DECL_IS_MALLOC (*node) = 1;
- /* ??? TODO: Support types. */
else
{
- warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
+ warning (OPT_Wattributes, "%qE attribute ignored", name);
+ *no_add_attrs = true;
+ }
+
+ return NULL_TREE;
+}
+
+/* Handle a "returns_twice" attribute; arguments as in
+ struct attribute_spec.handler. */
+
+static tree
+handle_returns_twice_attribute (tree *node, tree name, tree ARG_UNUSED (args),
+ int ARG_UNUSED (flags), bool *no_add_attrs)
+{
+ if (TREE_CODE (*node) == FUNCTION_DECL)
+ DECL_IS_RETURNS_TWICE (*node) = 1;
+ else
+ {
+ warning (OPT_Wattributes, "%qE attribute ignored", name);
*no_add_attrs = true;
}
@@ -5061,20 +5139,20 @@ handle_malloc_attribute (tree *node, tree name, tree args ATTRIBUTE_UNUSED,
static tree
handle_no_limit_stack_attribute (tree *node, tree name,
- tree args ATTRIBUTE_UNUSED,
- int flags ATTRIBUTE_UNUSED,
+ tree ARG_UNUSED (args),
+ int ARG_UNUSED (flags),
bool *no_add_attrs)
{
tree decl = *node;
if (TREE_CODE (decl) != FUNCTION_DECL)
{
- error ("%J'%E' attribute applies only to functions", decl, name);
+ error ("%J%qE attribute applies only to functions", decl, name);
*no_add_attrs = true;
}
else if (DECL_INITIAL (decl))
{
- error ("%Jcan't set '%E' attribute after definition", decl, name);
+ error ("%Jcan%'t set %qE attribute after definition", decl, name);
*no_add_attrs = true;
}
else
@@ -5087,32 +5165,45 @@ handle_no_limit_stack_attribute (tree *node, tree name,
struct attribute_spec.handler. */
static tree
-handle_pure_attribute (tree *node, tree name, tree args ATTRIBUTE_UNUSED,
- int flags ATTRIBUTE_UNUSED, bool *no_add_attrs)
+handle_pure_attribute (tree *node, tree name, tree ARG_UNUSED (args),
+ int ARG_UNUSED (flags), bool *no_add_attrs)
{
if (TREE_CODE (*node) == FUNCTION_DECL)
DECL_IS_PURE (*node) = 1;
/* ??? TODO: Support types. */
else
{
- warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
+ warning (OPT_Wattributes, "%qE attribute ignored", name);
*no_add_attrs = true;
}
return NULL_TREE;
}
+/* Handle a "no vops" attribute; arguments as in
+ struct attribute_spec.handler. */
+
+static tree
+handle_novops_attribute (tree *node, tree ARG_UNUSED (name),
+ tree ARG_UNUSED (args), int ARG_UNUSED (flags),
+ bool *ARG_UNUSED (no_add_attrs))
+{
+ gcc_assert (TREE_CODE (*node) == FUNCTION_DECL);
+ DECL_IS_NOVOPS (*node) = 1;
+ return NULL_TREE;
+}
+
/* Handle a "deprecated" attribute; arguments as in
struct attribute_spec.handler. */
static tree
handle_deprecated_attribute (tree *node, tree name,
- tree args ATTRIBUTE_UNUSED, int flags,
+ tree ARG_UNUSED (args), int flags,
bool *no_add_attrs)
{
tree type = NULL_TREE;
int warn = 0;
- const char *what = NULL;
+ tree what = NULL_TREE;
if (DECL_P (*node))
{
@@ -5131,7 +5222,7 @@ handle_deprecated_attribute (tree *node, tree name,
else if (TYPE_P (*node))
{
if (!(flags & (int) ATTR_FLAG_TYPE_IN_PLACE))
- *node = build_type_copy (*node);
+ *node = build_variant_type_copy (*node);
TREE_DEPRECATED (*node) = 1;
type = *node;
}
@@ -5144,52 +5235,44 @@ handle_deprecated_attribute (tree *node, tree name,
if (type && TYPE_NAME (type))
{
if (TREE_CODE (TYPE_NAME (type)) == IDENTIFIER_NODE)
- what = IDENTIFIER_POINTER (TYPE_NAME (*node));
+ what = TYPE_NAME (*node);
else if (TREE_CODE (TYPE_NAME (type)) == TYPE_DECL
&& DECL_NAME (TYPE_NAME (type)))
- what = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (type)));
+ what = DECL_NAME (TYPE_NAME (type));
}
if (what)
- warning ("`%s' attribute ignored for `%s'",
- IDENTIFIER_POINTER (name), what);
+ warning (OPT_Wattributes, "%qE attribute ignored for %qE", name, what);
else
- warning ("`%s' attribute ignored",
- IDENTIFIER_POINTER (name));
+ warning (OPT_Wattributes, "%qE attribute ignored", name);
}
return NULL_TREE;
}
-/* Keep a list of vector type nodes we created in handle_vector_size_attribute,
- to prevent us from duplicating type nodes unnecessarily.
- The normal mechanism to prevent duplicates is to use type_hash_canon, but
- since we want to distinguish types that are essentially identical (except
- for their debug representation), we use a local list here. */
-static GTY(()) tree vector_type_node_list = 0;
-
/* Handle a "vector_size" attribute; arguments as in
struct attribute_spec.handler. */
static tree
handle_vector_size_attribute (tree *node, tree name, tree args,
- int flags ATTRIBUTE_UNUSED,
+ int ARG_UNUSED (flags),
bool *no_add_attrs)
{
unsigned HOST_WIDE_INT vecsize, nunits;
- enum machine_mode mode, orig_mode, new_mode;
- tree type = *node, new_type = NULL_TREE;
- tree type_list_node;
+ enum machine_mode orig_mode;
+ tree type = *node, new_type, size;
*no_add_attrs = true;
- if (! host_integerp (TREE_VALUE (args), 1))
+ size = TREE_VALUE (args);
+
+ if (!host_integerp (size, 1))
{
- warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
+ warning (OPT_Wattributes, "%qE attribute ignored", name);
return NULL_TREE;
}
/* Get the vector size (in bytes). */
- vecsize = tree_low_cst (TREE_VALUE (args), 1);
+ vecsize = tree_low_cst (size, 1);
/* We need to provide for vector pointers, vector arrays, and
functions returning vectors. For example:
@@ -5209,100 +5292,38 @@ handle_vector_size_attribute (tree *node, tree name, tree args,
orig_mode = TYPE_MODE (type);
if (TREE_CODE (type) == RECORD_TYPE
- || (GET_MODE_CLASS (orig_mode) != MODE_FLOAT
+ || TREE_CODE (type) == UNION_TYPE
+ || TREE_CODE (type) == VECTOR_TYPE
+ || (!SCALAR_FLOAT_MODE_P (orig_mode)
&& GET_MODE_CLASS (orig_mode) != MODE_INT)
- || ! host_integerp (TYPE_SIZE_UNIT (type), 1))
+ || !host_integerp (TYPE_SIZE_UNIT (type), 1))
{
- error ("invalid vector type for attribute `%s'",
- IDENTIFIER_POINTER (name));
+ error ("invalid vector type for attribute %qE", name);
return NULL_TREE;
}
- /* Calculate how many units fit in the vector. */
- nunits = vecsize / tree_low_cst (TYPE_SIZE_UNIT (type), 1);
-
- /* Find a suitably sized vector. */
- new_mode = VOIDmode;
- for (mode = GET_CLASS_NARROWEST_MODE (GET_MODE_CLASS (orig_mode) == MODE_INT
- ? MODE_VECTOR_INT
- : MODE_VECTOR_FLOAT);
- mode != VOIDmode;
- mode = GET_MODE_WIDER_MODE (mode))
- if (vecsize == GET_MODE_SIZE (mode)
- && nunits == (unsigned HOST_WIDE_INT) GET_MODE_NUNITS (mode))
- {
- new_mode = mode;
- break;
- }
-
- if (new_mode == VOIDmode)
+ if (vecsize % tree_low_cst (TYPE_SIZE_UNIT (type), 1))
{
- error ("no vector mode with the size and type specified could be found");
- return NULL_TREE;
+ error ("vector size not an integral multiple of component size");
+ return NULL;
}
- for (type_list_node = vector_type_node_list; type_list_node;
- type_list_node = TREE_CHAIN (type_list_node))
+ if (vecsize == 0)
{
- tree other_type = TREE_VALUE (type_list_node);
- tree record = TYPE_DEBUG_REPRESENTATION_TYPE (other_type);
- tree fields = TYPE_FIELDS (record);
- tree field_type = TREE_TYPE (fields);
- tree array_type = TREE_TYPE (field_type);
- if (TREE_CODE (fields) != FIELD_DECL
- || TREE_CODE (field_type) != ARRAY_TYPE)
- abort ();
-
- if (TYPE_MODE (other_type) == mode && type == array_type)
- {
- new_type = other_type;
- break;
- }
+ error ("zero vector size");
+ return NULL;
}
- if (new_type == NULL_TREE)
+ /* Calculate how many units fit in the vector. */
+ nunits = vecsize / tree_low_cst (TYPE_SIZE_UNIT (type), 1);
+ if (nunits & (nunits - 1))
{
- tree index, array, rt, list_node;
-
- new_type = (*lang_hooks.types.type_for_mode) (new_mode,
- TREE_UNSIGNED (type));
-
- if (!new_type)
- {
- error ("no vector mode with the size and type specified could be found");
- return NULL_TREE;
- }
-
- new_type = build_type_copy (new_type);
-
- /* If this is a vector, make sure we either have hardware
- support, or we can emulate it. */
- if ((GET_MODE_CLASS (mode) == MODE_VECTOR_INT
- || GET_MODE_CLASS (mode) == MODE_VECTOR_FLOAT)
- && !vector_mode_valid_p (mode))
- {
- error ("unable to emulate '%s'", GET_MODE_NAME (mode));
- return NULL_TREE;
- }
-
- /* Set the debug information here, because this is the only
- place where we know the underlying type for a vector made
- with vector_size. For debugging purposes we pretend a vector
- is an array within a structure. */
- index = build_int_2 (TYPE_VECTOR_SUBPARTS (new_type) - 1, 0);
- array = build_array_type (type, build_index_type (index));
- rt = make_node (RECORD_TYPE);
-
- TYPE_FIELDS (rt) = build_decl (FIELD_DECL, get_identifier ("f"), array);
- DECL_CONTEXT (TYPE_FIELDS (rt)) = rt;
- layout_type (rt);
- TYPE_DEBUG_REPRESENTATION_TYPE (new_type) = rt;
-
- list_node = build_tree_list (NULL, new_type);
- TREE_CHAIN (list_node) = vector_type_node_list;
- vector_type_node_list = list_node;
+ error ("number of components of the vector not a power of two");
+ return NULL_TREE;
}
+ new_type = build_vector_type (type, nunits);
+
/* Build back pointers if needed. */
*node = reconstruct_complex_type (*node, new_type);
@@ -5311,8 +5332,8 @@ handle_vector_size_attribute (tree *node, tree name, tree args,
/* Handle the "nonnull" attribute. */
static tree
-handle_nonnull_attribute (tree *node, tree name ATTRIBUTE_UNUSED,
- tree args, int flags ATTRIBUTE_UNUSED,
+handle_nonnull_attribute (tree *node, tree ARG_UNUSED (name),
+ tree args, int ARG_UNUSED (flags),
bool *no_add_attrs)
{
tree type = *node;
@@ -5321,12 +5342,12 @@ handle_nonnull_attribute (tree *node, tree name ATTRIBUTE_UNUSED,
/* If no arguments are specified, all pointer arguments should be
non-null. Verify a full prototype is given so that the arguments
will have the correct types when we actually check them later. */
- if (! args)
+ if (!args)
{
- if (! TYPE_ARG_TYPES (type))
+ if (!TYPE_ARG_TYPES (type))
{
error ("nonnull attribute without arguments on a non-prototype");
- *no_add_attrs = true;
+ *no_add_attrs = true;
}
return NULL_TREE;
}
@@ -5336,11 +5357,11 @@ handle_nonnull_attribute (tree *node, tree name ATTRIBUTE_UNUSED,
for (attr_arg_num = 1; args; args = TREE_CHAIN (args))
{
tree argument;
- unsigned HOST_WIDE_INT arg_num, ck_num;
+ unsigned HOST_WIDE_INT arg_num = 0, ck_num;
- if (! get_nonnull_operand (TREE_VALUE (args), &arg_num))
+ if (!get_nonnull_operand (TREE_VALUE (args), &arg_num))
{
- error ("nonnull argument has invalid operand number (arg %lu)",
+ error ("nonnull argument has invalid operand number (argument %lu)",
(unsigned long) attr_arg_num);
*no_add_attrs = true;
return NULL_TREE;
@@ -5351,23 +5372,23 @@ handle_nonnull_attribute (tree *node, tree name ATTRIBUTE_UNUSED,
{
for (ck_num = 1; ; ck_num++)
{
- if (! argument || ck_num == arg_num)
+ if (!argument || ck_num == arg_num)
break;
argument = TREE_CHAIN (argument);
}
- if (! argument
+ if (!argument
|| TREE_CODE (TREE_VALUE (argument)) == VOID_TYPE)
{
- error ("nonnull argument with out-of-range operand number (arg %lu, operand %lu)",
+ error ("nonnull argument with out-of-range operand number (argument %lu, operand %lu)",
(unsigned long) attr_arg_num, (unsigned long) arg_num);
*no_add_attrs = true;
return NULL_TREE;
}
- if (TREE_CODE (TREE_VALUE (argument)) != POINTER_TYPE)
+ if (TREE_CODE (TREE_VALUE (argument)) != POINTER_TYPE)
{
- error ("nonnull argument references non-pointer operand (arg %lu, operand %lu)",
+ error ("nonnull argument references non-pointer operand (argument %lu, operand %lu)",
(unsigned long) attr_arg_num, (unsigned long) arg_num);
*no_add_attrs = true;
return NULL_TREE;
@@ -5391,22 +5412,90 @@ check_function_nonnull (tree attrs, tree params)
{
if (is_attribute_p ("nonnull", TREE_PURPOSE (a)))
{
- args = TREE_VALUE (a);
+ args = TREE_VALUE (a);
- /* Walk the argument list. If we encounter an argument number we
- should check for non-null, do it. If the attribute has no args,
- then every pointer argument is checked (in which case the check
+ /* Walk the argument list. If we encounter an argument number we
+ should check for non-null, do it. If the attribute has no args,
+ then every pointer argument is checked (in which case the check
for pointer type is done in check_nonnull_arg). */
- for (param = params, param_num = 1; ;
- param_num++, param = TREE_CHAIN (param))
- {
- if (! param)
+ for (param = params, param_num = 1; ;
+ param_num++, param = TREE_CHAIN (param))
+ {
+ if (!param)
break;
- if (! args || nonnull_check_p (args, param_num))
+ if (!args || nonnull_check_p (args, param_num))
check_function_arguments_recurse (check_nonnull_arg, NULL,
TREE_VALUE (param),
param_num);
- }
+ }
+ }
+ }
+}
+
+/* Check that the Nth argument of a function call (counting backwards
+ from the end) is a (pointer)0. */
+
+static void
+check_function_sentinel (tree attrs, tree params, tree typelist)
+{
+ tree attr = lookup_attribute ("sentinel", attrs);
+
+ if (attr)
+ {
+ /* Skip over the named arguments. */
+ while (typelist && params)
+ {
+ typelist = TREE_CHAIN (typelist);
+ params = TREE_CHAIN (params);
+ }
+
+ if (typelist || !params)
+ warning (OPT_Wformat,
+ "not enough variable arguments to fit a sentinel");
+ else
+ {
+ tree sentinel, end;
+ unsigned pos = 0;
+
+ if (TREE_VALUE (attr))
+ {
+ tree p = TREE_VALUE (TREE_VALUE (attr));
+ pos = TREE_INT_CST_LOW (p);
+ }
+
+ sentinel = end = params;
+
+ /* Advance `end' ahead of `sentinel' by `pos' positions. */
+ while (pos > 0 && TREE_CHAIN (end))
+ {
+ pos--;
+ end = TREE_CHAIN (end);
+ }
+ if (pos > 0)
+ {
+ warning (OPT_Wformat,
+ "not enough variable arguments to fit a sentinel");
+ return;
+ }
+
+ /* Now advance both until we find the last parameter. */
+ while (TREE_CHAIN (end))
+ {
+ end = TREE_CHAIN (end);
+ sentinel = TREE_CHAIN (sentinel);
+ }
+
+ /* Validate the sentinel. */
+ if ((!POINTER_TYPE_P (TREE_TYPE (TREE_VALUE (sentinel)))
+ || !integer_zerop (TREE_VALUE (sentinel)))
+ /* Although __null (in C++) is only an integer we allow it
+ nevertheless, as we are guaranteed that it's exactly
+ as wide as a pointer, and we don't want to force
+ users to cast the NULL they have written there.
+ We warn with -Wstrict-null-sentinel, though. */
+ && (warn_strict_null_sentinel
+ || null_node != TREE_VALUE (sentinel)))
+ warning (OPT_Wformat, "missing sentinel in function call");
}
}
}
@@ -5418,12 +5507,13 @@ check_function_nonnull (tree attrs, tree params)
static bool
nonnull_check_p (tree args, unsigned HOST_WIDE_INT param_num)
{
- unsigned HOST_WIDE_INT arg_num;
+ unsigned HOST_WIDE_INT arg_num = 0;
for (; args; args = TREE_CHAIN (args))
{
- if (! get_nonnull_operand (TREE_VALUE (args), &arg_num))
- abort ();
+ bool found = get_nonnull_operand (TREE_VALUE (args), &arg_num);
+
+ gcc_assert (found);
if (arg_num == param_num)
return true;
@@ -5436,7 +5526,7 @@ nonnull_check_p (tree args, unsigned HOST_WIDE_INT param_num)
via check_function_arguments_recurse. */
static void
-check_nonnull_arg (void *ctx ATTRIBUTE_UNUSED, tree param,
+check_nonnull_arg (void * ARG_UNUSED (ctx), tree param,
unsigned HOST_WIDE_INT param_num)
{
/* Just skip checking the argument if it's not a pointer. This can
@@ -5447,8 +5537,8 @@ check_nonnull_arg (void *ctx ATTRIBUTE_UNUSED, tree param,
return;
if (integer_zerop (param))
- warning ("null argument where non-null required (arg %lu)",
- (unsigned long) param_num);
+ warning (OPT_Wnonnull, "null argument where non-null required "
+ "(argument %lu)", (unsigned long) param_num);
}
/* Helper for nonnull attribute handling; fetch the operand number
@@ -5457,13 +5547,7 @@ check_nonnull_arg (void *ctx ATTRIBUTE_UNUSED, tree param,
static bool
get_nonnull_operand (tree arg_num_expr, unsigned HOST_WIDE_INT *valp)
{
- /* Strip any conversions from the arg number and verify they
- are constants. */
- while (TREE_CODE (arg_num_expr) == NOP_EXPR
- || TREE_CODE (arg_num_expr) == CONVERT_EXPR
- || TREE_CODE (arg_num_expr) == NON_LVALUE_EXPR)
- arg_num_expr = TREE_OPERAND (arg_num_expr, 0);
-
+ /* Verify the arg number is a constant. */
if (TREE_CODE (arg_num_expr) != INTEGER_CST
|| TREE_INT_CST_HIGH (arg_num_expr) != 0)
return false;
@@ -5476,15 +5560,15 @@ get_nonnull_operand (tree arg_num_expr, unsigned HOST_WIDE_INT *valp)
struct attribute_spec.handler. */
static tree
-handle_nothrow_attribute (tree *node, tree name, tree args ATTRIBUTE_UNUSED,
- int flags ATTRIBUTE_UNUSED, bool *no_add_attrs)
+handle_nothrow_attribute (tree *node, tree name, tree ARG_UNUSED (args),
+ int ARG_UNUSED (flags), bool *no_add_attrs)
{
if (TREE_CODE (*node) == FUNCTION_DECL)
TREE_NOTHROW (*node) = 1;
/* ??? TODO: Support types. */
else
{
- warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
+ warning (OPT_Wattributes, "%qE attribute ignored", name);
*no_add_attrs = true;
}
@@ -5496,7 +5580,7 @@ handle_nothrow_attribute (tree *node, tree name, tree args ATTRIBUTE_UNUSED,
static tree
handle_cleanup_attribute (tree *node, tree name, tree args,
- int flags ATTRIBUTE_UNUSED, bool *no_add_attrs)
+ int ARG_UNUSED (flags), bool *no_add_attrs)
{
tree decl = *node;
tree cleanup_id, cleanup_decl;
@@ -5507,7 +5591,7 @@ handle_cleanup_attribute (tree *node, tree name, tree args,
we'd be missing too much, since we do have attribute constructor. */
if (TREE_CODE (decl) != VAR_DECL || TREE_STATIC (decl))
{
- warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
+ warning (OPT_Wattributes, "%qE attribute ignored", name);
*no_add_attrs = true;
return NULL_TREE;
}
@@ -5518,14 +5602,14 @@ handle_cleanup_attribute (tree *node, tree name, tree args,
cleanup_id = TREE_VALUE (args);
if (TREE_CODE (cleanup_id) != IDENTIFIER_NODE)
{
- error ("cleanup arg not an identifier");
+ error ("cleanup argument not an identifier");
*no_add_attrs = true;
return NULL_TREE;
}
cleanup_decl = lookup_name (cleanup_id);
if (!cleanup_decl || TREE_CODE (cleanup_decl) != FUNCTION_DECL)
{
- error ("cleanup arg not a function");
+ error ("cleanup argument not a function");
*no_add_attrs = true;
return NULL_TREE;
}
@@ -5540,22 +5624,71 @@ handle_cleanup_attribute (tree *node, tree name, tree args,
static tree
handle_warn_unused_result_attribute (tree *node, tree name,
- tree args ATTRIBUTE_UNUSED,
- int flags ATTRIBUTE_UNUSED, bool *no_add_attrs)
+ tree ARG_UNUSED (args),
+ int ARG_UNUSED (flags), bool *no_add_attrs)
{
/* Ignore the attribute for functions not returning any value. */
if (VOID_TYPE_P (TREE_TYPE (*node)))
{
- warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
+ warning (OPT_Wattributes, "%qE attribute ignored", name);
*no_add_attrs = true;
}
return NULL_TREE;
}
+
+/* Handle a "sentinel" attribute. */
+
+static tree
+handle_sentinel_attribute (tree *node, tree name, tree args,
+ int ARG_UNUSED (flags), bool *no_add_attrs)
+{
+ tree params = TYPE_ARG_TYPES (*node);
+
+ if (!params)
+ {
+ warning (OPT_Wattributes,
+ "%qE attribute requires prototypes with named arguments", name);
+ *no_add_attrs = true;
+ }
+ else
+ {
+ while (TREE_CHAIN (params))
+ params = TREE_CHAIN (params);
+
+ if (VOID_TYPE_P (TREE_VALUE (params)))
+ {
+ warning (OPT_Wattributes,
+ "%qE attribute only applies to variadic functions", name);
+ *no_add_attrs = true;
+ }
+ }
+
+ if (args)
+ {
+ tree position = TREE_VALUE (args);
+
+ if (TREE_CODE (position) != INTEGER_CST)
+ {
+ warning (0, "requested position is not an integer constant");
+ *no_add_attrs = true;
+ }
+ else
+ {
+ if (tree_int_cst_lt (position, integer_zero_node))
+ {
+ warning (0, "requested position is less than zero");
+ *no_add_attrs = true;
+ }
+ }
+ }
+
+ return NULL_TREE;
+}
/* Check for valid arguments being passed to a function. */
void
-check_function_arguments (tree attrs, tree params)
+check_function_arguments (tree attrs, tree params, tree typelist)
{
/* Check for null being passed in a pointer argument that must be
non-null. We also need to do this if format checking is enabled. */
@@ -5565,8 +5698,11 @@ check_function_arguments (tree attrs, tree params)
/* Check for errors in format strings. */
+ if (warn_format || warn_missing_format_attribute)
+ check_function_format (attrs, params);
+
if (warn_format)
- check_function_format (NULL, attrs, params);
+ check_function_sentinel (attrs, params, typelist);
}
/* Generic argument checking recursion routine. PARAM is the argument to
@@ -5578,11 +5714,13 @@ check_function_arguments_recurse (void (*callback)
void *ctx, tree param,
unsigned HOST_WIDE_INT param_num)
{
- if (TREE_CODE (param) == NOP_EXPR)
+ if ((TREE_CODE (param) == NOP_EXPR || TREE_CODE (param) == CONVERT_EXPR)
+ && (TYPE_PRECISION (TREE_TYPE (param))
+ == TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (param, 0)))))
{
/* Strip coercion. */
check_function_arguments_recurse (callback, ctx,
- TREE_OPERAND (param, 0), param_num);
+ TREE_OPERAND (param, 0), param_num);
return;
}
@@ -5609,14 +5747,9 @@ check_function_arguments_recurse (void (*callback)
/* Extract the argument number, which was previously checked
to be valid. */
format_num_expr = TREE_VALUE (TREE_VALUE (attrs));
- while (TREE_CODE (format_num_expr) == NOP_EXPR
- || TREE_CODE (format_num_expr) == CONVERT_EXPR
- || TREE_CODE (format_num_expr) == NON_LVALUE_EXPR)
- format_num_expr = TREE_OPERAND (format_num_expr, 0);
- if (TREE_CODE (format_num_expr) != INTEGER_CST
- || TREE_INT_CST_HIGH (format_num_expr) != 0)
- abort ();
+ gcc_assert (TREE_CODE (format_num_expr) == INTEGER_CST
+ && !TREE_INT_CST_HIGH (format_num_expr));
format_num = TREE_INT_CST_LOW (format_num_expr);
@@ -5644,9 +5777,9 @@ check_function_arguments_recurse (void (*callback)
{
/* Check both halves of the conditional expression. */
check_function_arguments_recurse (callback, ctx,
- TREE_OPERAND (param, 1), param_num);
+ TREE_OPERAND (param, 1), param_num);
check_function_arguments_recurse (callback, ctx,
- TREE_OPERAND (param, 2), param_num);
+ TREE_OPERAND (param, 2), param_num);
return;
}
@@ -5658,8 +5791,9 @@ check_function_arguments_recurse (void (*callback)
int
field_decl_cmp (const void *x_p, const void *y_p)
{
- const tree *const x = x_p;
- const tree *const y = y_p;
+ const tree *const x = (const tree *const) x_p;
+ const tree *const y = (const tree *const) y_p;
+
if (DECL_NAME (*x) == DECL_NAME (*y))
/* A nontype is "greater" than a type. */
return (TREE_CODE (*y) == TYPE_DECL) - (TREE_CODE (*x) == TYPE_DECL);
@@ -5683,8 +5817,8 @@ pointer operator in resort_data. */
static int
resort_field_decl_cmp (const void *x_p, const void *y_p)
{
- const tree *const x = x_p;
- const tree *const y = y_p;
+ const tree *const x = (const tree *const) x_p;
+ const tree *const y = (const tree *const) y_p;
if (DECL_NAME (*x) == DECL_NAME (*y))
/* A nontype is "greater" than a type. */
@@ -5708,205 +5842,634 @@ resort_field_decl_cmp (const void *x_p, const void *y_p)
void
resort_sorted_fields (void *obj,
- void *orig_obj ATTRIBUTE_UNUSED ,
- gt_pointer_operator new_value,
- void *cookie)
+ void * ARG_UNUSED (orig_obj),
+ gt_pointer_operator new_value,
+ void *cookie)
{
- struct sorted_fields_type *sf = obj;
+ struct sorted_fields_type *sf = (struct sorted_fields_type *) obj;
resort_data.new_value = new_value;
resort_data.cookie = cookie;
qsort (&sf->elts[0], sf->len, sizeof (tree),
- resort_field_decl_cmp);
+ resort_field_decl_cmp);
}
-/* Used by estimate_num_insns. Estimate number of instructions seen
- by given statement. */
-static tree
-c_estimate_num_insns_1 (tree *tp, int *walk_subtrees, void *data)
+/* Subroutine of c_parse_error.
+ Return the result of concatenating LHS and RHS. RHS is really
+ a string literal, its first character is indicated by RHS_START and
+ RHS_SIZE is its length (including the terminating NUL character).
+
+ The caller is responsible for deleting the returned pointer. */
+
+static char *
+catenate_strings (const char *lhs, const char *rhs_start, int rhs_size)
{
- int *count = data;
- tree x = *tp;
+ const int lhs_size = strlen (lhs);
+ char *result = XNEWVEC (char, lhs_size + rhs_size);
+ strncpy (result, lhs, lhs_size);
+ strncpy (result + lhs_size, rhs_start, rhs_size);
+ return result;
+}
+
+/* Issue the error given by GMSGID, indicating that it occurred before
+ TOKEN, which had the associated VALUE. */
+
+void
+c_parse_error (const char *gmsgid, enum cpp_ttype token, tree value)
+{
+#define catenate_messages(M1, M2) catenate_strings ((M1), (M2), sizeof (M2))
+
+ char *message = NULL;
- if (TYPE_P (x) || DECL_P (x))
+ if (token == CPP_EOF)
+ message = catenate_messages (gmsgid, " at end of input");
+ else if (token == CPP_CHAR || token == CPP_WCHAR)
{
- *walk_subtrees = 0;
- return NULL;
+ unsigned int val = TREE_INT_CST_LOW (value);
+ const char *const ell = (token == CPP_CHAR) ? "" : "L";
+ if (val <= UCHAR_MAX && ISGRAPH (val))
+ message = catenate_messages (gmsgid, " before %s'%c'");
+ else
+ message = catenate_messages (gmsgid, " before %s'\\x%x'");
+
+ error (message, ell, val);
+ free (message);
+ message = NULL;
}
- /* Assume that constants and references counts nothing. These should
- be majorized by amount of operations among them we count later
- and are common target of CSE and similar optimizations. */
- if (TREE_CODE_CLASS (TREE_CODE (x)) == 'c'
- || TREE_CODE_CLASS (TREE_CODE (x)) == 'r')
- return NULL;
- switch (TREE_CODE (x))
- {
- /* Recognize assignments of large structures and constructors of
- big arrays. */
- case MODIFY_EXPR:
- case CONSTRUCTOR:
- {
- HOST_WIDE_INT size;
+ else if (token == CPP_STRING || token == CPP_WSTRING)
+ message = catenate_messages (gmsgid, " before string constant");
+ else if (token == CPP_NUMBER)
+ message = catenate_messages (gmsgid, " before numeric constant");
+ else if (token == CPP_NAME)
+ {
+ message = catenate_messages (gmsgid, " before %qE");
+ error (message, value);
+ free (message);
+ message = NULL;
+ }
+ else if (token == CPP_PRAGMA)
+ message = catenate_messages (gmsgid, " before %<#pragma%>");
+ else if (token == CPP_PRAGMA_EOL)
+ message = catenate_messages (gmsgid, " before end of line");
+ else if (token < N_TTYPES)
+ {
+ message = catenate_messages (gmsgid, " before %qs token");
+ error (message, cpp_type2name (token));
+ free (message);
+ message = NULL;
+ }
+ else
+ error (gmsgid);
- size = int_size_in_bytes (TREE_TYPE (x));
+ if (message)
+ {
+ error (message);
+ free (message);
+ }
+#undef catenate_messages
+}
- if (size < 0 || size > MOVE_MAX_PIECES * MOVE_RATIO)
- *count += 10;
- else
- *count += ((size + MOVE_MAX_PIECES - 1) / MOVE_MAX_PIECES);
- }
+/* Walk a gimplified function and warn for functions whose return value is
+ ignored and attribute((warn_unused_result)) is set. This is done before
+ inlining, so we don't have to worry about that. */
+
+void
+c_warn_unused_result (tree *top_p)
+{
+ tree t = *top_p;
+ tree_stmt_iterator i;
+ tree fdecl, ftype;
+
+ switch (TREE_CODE (t))
+ {
+ case STATEMENT_LIST:
+ for (i = tsi_start (*top_p); !tsi_end_p (i); tsi_next (&i))
+ c_warn_unused_result (tsi_stmt_ptr (i));
break;
- case CALL_EXPR:
- {
- tree decl = get_callee_fndecl (x);
- if (decl && DECL_BUILT_IN (decl))
- switch (DECL_FUNCTION_CODE (decl))
- {
- case BUILT_IN_CONSTANT_P:
- *walk_subtrees = 0;
- return NULL_TREE;
- case BUILT_IN_EXPECT:
- return NULL_TREE;
- default:
- break;
- }
- *count += 10;
- break;
- }
- /* Few special cases of expensive operations. This is usefull
- to avoid inlining on functions having too many of these. */
- case TRUNC_DIV_EXPR:
- case CEIL_DIV_EXPR:
- case FLOOR_DIV_EXPR:
- case ROUND_DIV_EXPR:
- case TRUNC_MOD_EXPR:
- case CEIL_MOD_EXPR:
- case FLOOR_MOD_EXPR:
- case ROUND_MOD_EXPR:
- case RDIV_EXPR:
- *count += 10;
+ case COND_EXPR:
+ c_warn_unused_result (&COND_EXPR_THEN (t));
+ c_warn_unused_result (&COND_EXPR_ELSE (t));
break;
- /* Various containers that will produce no code themselves. */
- case INIT_EXPR:
- case TARGET_EXPR:
case BIND_EXPR:
- case BLOCK:
- case TREE_LIST:
- case TREE_VEC:
- case IDENTIFIER_NODE:
- case PLACEHOLDER_EXPR:
- case WITH_CLEANUP_EXPR:
- case CLEANUP_POINT_EXPR:
- case NOP_EXPR:
- case VIEW_CONVERT_EXPR:
- case SAVE_EXPR:
- case UNSAVE_EXPR:
- case COMPLEX_EXPR:
- case REALPART_EXPR:
- case IMAGPART_EXPR:
- case TRY_CATCH_EXPR:
+ c_warn_unused_result (&BIND_EXPR_BODY (t));
+ break;
case TRY_FINALLY_EXPR:
- case LABEL_EXPR:
- case EXIT_EXPR:
- case LABELED_BLOCK_EXPR:
- case EXIT_BLOCK_EXPR:
- case EXPR_WITH_FILE_LOCATION:
-
- case EXPR_STMT:
- case COMPOUND_STMT:
- case RETURN_STMT:
- case LABEL_STMT:
- case SCOPE_STMT:
- case FILE_STMT:
- case CASE_LABEL:
- case STMT_EXPR:
- case CLEANUP_STMT:
-
- case SIZEOF_EXPR:
- case ARROW_EXPR:
- case ALIGNOF_EXPR:
+ case TRY_CATCH_EXPR:
+ c_warn_unused_result (&TREE_OPERAND (t, 0));
+ c_warn_unused_result (&TREE_OPERAND (t, 1));
+ break;
+ case CATCH_EXPR:
+ c_warn_unused_result (&CATCH_BODY (t));
+ break;
+ case EH_FILTER_EXPR:
+ c_warn_unused_result (&EH_FILTER_FAILURE (t));
+ break;
+
+ case CALL_EXPR:
+ if (TREE_USED (t))
+ break;
+
+ /* This is a naked call, as opposed to a CALL_EXPR nested inside
+ a MODIFY_EXPR. All calls whose value is ignored should be
+ represented like this. Look for the attribute. */
+ fdecl = get_callee_fndecl (t);
+ if (fdecl)
+ ftype = TREE_TYPE (fdecl);
+ else
+ {
+ ftype = TREE_TYPE (TREE_OPERAND (t, 0));
+ /* Look past pointer-to-function to the function type itself. */
+ ftype = TREE_TYPE (ftype);
+ }
+
+ if (lookup_attribute ("warn_unused_result", TYPE_ATTRIBUTES (ftype)))
+ {
+ if (fdecl)
+ warning (0, "%Hignoring return value of %qD, "
+ "declared with attribute warn_unused_result",
+ EXPR_LOCUS (t), fdecl);
+ else
+ warning (0, "%Hignoring return value of function "
+ "declared with attribute warn_unused_result",
+ EXPR_LOCUS (t));
+ }
+ break;
+
+ default:
+ /* Not a container, not a call, or a call whose value is used. */
+ break;
+ }
+}
+
+/* Convert a character from the host to the target execution character
+ set. cpplib handles this, mostly. */
+
+HOST_WIDE_INT
+c_common_to_target_charset (HOST_WIDE_INT c)
+{
+ /* Character constants in GCC proper are sign-extended under -fsigned-char,
+ zero-extended under -fno-signed-char. cpplib insists that characters
+ and character constants are always unsigned. Hence we must convert
+ back and forth. */
+ cppchar_t uc = ((cppchar_t)c) & ((((cppchar_t)1) << CHAR_BIT)-1);
+
+ uc = cpp_host_to_exec_charset (parse_in, uc);
+
+ if (flag_signed_char)
+ return ((HOST_WIDE_INT)uc) << (HOST_BITS_PER_WIDE_INT - CHAR_TYPE_SIZE)
+ >> (HOST_BITS_PER_WIDE_INT - CHAR_TYPE_SIZE);
+ else
+ return uc;
+}
+
+/* Build the result of __builtin_offsetof. EXPR is a nested sequence of
+ component references, with STOP_REF, or alternatively an INDIRECT_REF of
+ NULL, at the bottom; much like the traditional rendering of offsetof as a
+ macro. Returns the folded and properly cast result. */
+
+static tree
+fold_offsetof_1 (tree expr, tree stop_ref)
+{
+ enum tree_code code = PLUS_EXPR;
+ tree base, off, t;
+
+ if (expr == stop_ref && TREE_CODE (expr) != ERROR_MARK)
+ return size_zero_node;
+
+ switch (TREE_CODE (expr))
+ {
+ case ERROR_MARK:
+ return expr;
+
+ case VAR_DECL:
+ error ("cannot apply %<offsetof%> to static data member %qD", expr);
+ return error_mark_node;
+
+ case CALL_EXPR:
+ error ("cannot apply %<offsetof%> when %<operator[]%> is overloaded");
+ return error_mark_node;
+
+ case INTEGER_CST:
+ gcc_assert (integer_zerop (expr));
+ return size_zero_node;
+
+ case NOP_EXPR:
+ case INDIRECT_REF:
+ base = fold_offsetof_1 (TREE_OPERAND (expr, 0), stop_ref);
+ gcc_assert (base == error_mark_node || base == size_zero_node);
+ return base;
+
+ case COMPONENT_REF:
+ base = fold_offsetof_1 (TREE_OPERAND (expr, 0), stop_ref);
+ if (base == error_mark_node)
+ return base;
+
+ t = TREE_OPERAND (expr, 1);
+ if (DECL_C_BIT_FIELD (t))
+ {
+ error ("attempt to take address of bit-field structure "
+ "member %qD", t);
+ return error_mark_node;
+ }
+ off = size_binop (PLUS_EXPR, DECL_FIELD_OFFSET (t),
+ size_int (tree_low_cst (DECL_FIELD_BIT_OFFSET (t), 1)
+ / BITS_PER_UNIT));
+ break;
+
+ case ARRAY_REF:
+ base = fold_offsetof_1 (TREE_OPERAND (expr, 0), stop_ref);
+ if (base == error_mark_node)
+ return base;
+
+ t = TREE_OPERAND (expr, 1);
+ if (TREE_CODE (t) == INTEGER_CST && tree_int_cst_sgn (t) < 0)
+ {
+ code = MINUS_EXPR;
+ t = fold_build1 (NEGATE_EXPR, TREE_TYPE (t), t);
+ }
+ t = convert (sizetype, t);
+ off = size_binop (MULT_EXPR, TYPE_SIZE_UNIT (TREE_TYPE (expr)), t);
+ break;
+
+ case COMPOUND_EXPR:
+ /* Handle static members of volatile structs. */
+ t = TREE_OPERAND (expr, 1);
+ gcc_assert (TREE_CODE (t) == VAR_DECL);
+ return fold_offsetof_1 (t, stop_ref);
+
+ default:
+ gcc_unreachable ();
+ }
+
+ return size_binop (code, base, off);
+}
+
+tree
+fold_offsetof (tree expr, tree stop_ref)
+{
+ /* Convert back from the internal sizetype to size_t. */
+ return convert (size_type_node, fold_offsetof_1 (expr, stop_ref));
+}
+
+/* Print an error message for an invalid lvalue. USE says
+ how the lvalue is being used and so selects the error message. */
+
+void
+lvalue_error (enum lvalue_use use)
+{
+ switch (use)
+ {
+ case lv_assign:
+ error ("lvalue required as left operand of assignment");
+ break;
+ case lv_increment:
+ error ("lvalue required as increment operand");
+ break;
+ case lv_decrement:
+ error ("lvalue required as decrement operand");
break;
- case DECL_STMT:
- /* Do not account static initializers. */
- if (TREE_STATIC (TREE_OPERAND (x, 0)))
- *walk_subtrees = 0;
+ case lv_addressof:
+ error ("lvalue required as unary %<&%> operand");
+ break;
+ case lv_asm:
+ error ("lvalue required in asm statement");
break;
default:
- (*count)++;
+ gcc_unreachable ();
}
- return NULL;
}
+
+/* *PTYPE is an incomplete array. Complete it with a domain based on
+ INITIAL_VALUE. If INITIAL_VALUE is not present, use 1 if DO_DEFAULT
+ is true. Return 0 if successful, 1 if INITIAL_VALUE can't be deciphered,
+ 2 if INITIAL_VALUE was NULL, and 3 if INITIAL_VALUE was empty. */
-/* Estimate number of instructions that will be created by expanding the body. */
int
-c_estimate_num_insns (tree decl)
+complete_array_type (tree *ptype, tree initial_value, bool do_default)
+{
+ tree maxindex, type, main_type, elt, unqual_elt;
+ int failure = 0, quals;
+
+ maxindex = size_zero_node;
+ if (initial_value)
+ {
+ if (TREE_CODE (initial_value) == STRING_CST)
+ {
+ int eltsize
+ = int_size_in_bytes (TREE_TYPE (TREE_TYPE (initial_value)));
+ maxindex = size_int (TREE_STRING_LENGTH (initial_value)/eltsize - 1);
+ }
+ else if (TREE_CODE (initial_value) == CONSTRUCTOR)
+ {
+ VEC(constructor_elt,gc) *v = CONSTRUCTOR_ELTS (initial_value);
+
+ if (VEC_empty (constructor_elt, v))
+ {
+ if (pedantic)
+ failure = 3;
+ maxindex = integer_minus_one_node;
+ }
+ else
+ {
+ tree curindex;
+ unsigned HOST_WIDE_INT cnt;
+ constructor_elt *ce;
+
+ if (VEC_index (constructor_elt, v, 0)->index)
+ maxindex = fold_convert (sizetype,
+ VEC_index (constructor_elt,
+ v, 0)->index);
+ curindex = maxindex;
+
+ for (cnt = 1;
+ VEC_iterate (constructor_elt, v, cnt, ce);
+ cnt++)
+ {
+ if (ce->index)
+ curindex = fold_convert (sizetype, ce->index);
+ else
+ curindex = size_binop (PLUS_EXPR, curindex, size_one_node);
+
+ if (tree_int_cst_lt (maxindex, curindex))
+ maxindex = curindex;
+ }
+ }
+ }
+ else
+ {
+ /* Make an error message unless that happened already. */
+ if (initial_value != error_mark_node)
+ failure = 1;
+ }
+ }
+ else
+ {
+ failure = 2;
+ if (!do_default)
+ return failure;
+ }
+
+ type = *ptype;
+ elt = TREE_TYPE (type);
+ quals = TYPE_QUALS (strip_array_types (elt));
+ if (quals == 0)
+ unqual_elt = elt;
+ else
+ unqual_elt = c_build_qualified_type (elt, TYPE_UNQUALIFIED);
+
+ /* Using build_distinct_type_copy and modifying things afterward instead
+ of using build_array_type to create a new type preserves all of the
+ TYPE_LANG_FLAG_? bits that the front end may have set. */
+ main_type = build_distinct_type_copy (TYPE_MAIN_VARIANT (type));
+ TREE_TYPE (main_type) = unqual_elt;
+ TYPE_DOMAIN (main_type) = build_index_type (maxindex);
+ layout_type (main_type);
+
+ if (quals == 0)
+ type = main_type;
+ else
+ type = c_build_qualified_type (main_type, quals);
+
+ *ptype = type;
+ return failure;
+}
+
+
+/* Used to help initialize the builtin-types.def table. When a type of
+ the correct size doesn't exist, use error_mark_node instead of NULL.
+ The later results in segfaults even when a decl using the type doesn't
+ get invoked. */
+
+tree
+builtin_type_for_size (int size, bool unsignedp)
+{
+ tree type = lang_hooks.types.type_for_size (size, unsignedp);
+ return type ? type : error_mark_node;
+}
+
+/* A helper function for resolve_overloaded_builtin in resolving the
+ overloaded __sync_ builtins. Returns a positive power of 2 if the
+ first operand of PARAMS is a pointer to a supported data type.
+ Returns 0 if an error is encountered. */
+
+static int
+sync_resolve_size (tree function, tree params)
{
- int num = 0;
- walk_tree_without_duplicates (&DECL_SAVED_TREE (decl), c_estimate_num_insns_1, &num);
- return num;
+ tree type;
+ int size;
+
+ if (params == NULL)
+ {
+ error ("too few arguments to function %qE", function);
+ return 0;
+ }
+
+ type = TREE_TYPE (TREE_VALUE (params));
+ if (TREE_CODE (type) != POINTER_TYPE)
+ goto incompatible;
+
+ type = TREE_TYPE (type);
+ if (!INTEGRAL_TYPE_P (type) && !POINTER_TYPE_P (type))
+ goto incompatible;
+
+ size = tree_low_cst (TYPE_SIZE_UNIT (type), 1);
+ if (size == 1 || size == 2 || size == 4 || size == 8 || size == 16)
+ return size;
+
+ incompatible:
+ error ("incompatible type for argument %d of %qE", 1, function);
+ return 0;
+}
+
+/* A helper function for resolve_overloaded_builtin. Adds casts to
+ PARAMS to make arguments match up with those of FUNCTION. Drops
+ the variadic arguments at the end. Returns false if some error
+ was encountered; true on success. */
+
+static bool
+sync_resolve_params (tree orig_function, tree function, tree params)
+{
+ tree arg_types = TYPE_ARG_TYPES (TREE_TYPE (function));
+ tree ptype;
+ int number;
+
+ /* We've declared the implementation functions to use "volatile void *"
+ as the pointer parameter, so we shouldn't get any complaints from the
+ call to check_function_arguments what ever type the user used. */
+ arg_types = TREE_CHAIN (arg_types);
+ ptype = TREE_TYPE (TREE_TYPE (TREE_VALUE (params)));
+ number = 2;
+
+ /* For the rest of the values, we need to cast these to FTYPE, so that we
+ don't get warnings for passing pointer types, etc. */
+ while (arg_types != void_list_node)
+ {
+ tree val;
+
+ params = TREE_CHAIN (params);
+ if (params == NULL)
+ {
+ error ("too few arguments to function %qE", orig_function);
+ return false;
+ }
+
+ /* ??? Ideally for the first conversion we'd use convert_for_assignment
+ so that we get warnings for anything that doesn't match the pointer
+ type. This isn't portable across the C and C++ front ends atm. */
+ val = TREE_VALUE (params);
+ val = convert (ptype, val);
+ val = convert (TREE_VALUE (arg_types), val);
+ TREE_VALUE (params) = val;
+
+ arg_types = TREE_CHAIN (arg_types);
+ number++;
+ }
+
+ /* The definition of these primitives is variadic, with the remaining
+ being "an optional list of variables protected by the memory barrier".
+ No clue what that's supposed to mean, precisely, but we consider all
+ call-clobbered variables to be protected so we're safe. */
+ TREE_CHAIN (params) = NULL;
+
+ return true;
}
-/* Used by c_decl_uninit to find where expressions like x = x + 1; */
+/* A helper function for resolve_overloaded_builtin. Adds a cast to
+ RESULT to make it match the type of the first pointer argument in
+ PARAMS. */
static tree
-c_decl_uninit_1 (tree *t, int *walk_sub_trees, void *x)
+sync_resolve_return (tree params, tree result)
{
- /* If x = EXP(&x)EXP, then do not warn about the use of x. */
- if (TREE_CODE (*t) == ADDR_EXPR && TREE_OPERAND (*t, 0) == x)
+ tree ptype = TREE_TYPE (TREE_TYPE (TREE_VALUE (params)));
+ ptype = TYPE_MAIN_VARIANT (ptype);
+ return convert (ptype, result);
+}
+
+/* Some builtin functions are placeholders for other expressions. This
+ function should be called immediately after parsing the call expression
+ before surrounding code has committed to the type of the expression.
+
+ FUNCTION is the DECL that has been invoked; it is known to be a builtin.
+ PARAMS is the argument list for the call. The return value is non-null
+ when expansion is complete, and null if normal processing should
+ continue. */
+
+tree
+resolve_overloaded_builtin (tree function, tree params)
+{
+ enum built_in_function orig_code = DECL_FUNCTION_CODE (function);
+ switch (DECL_BUILT_IN_CLASS (function))
{
- *walk_sub_trees = 0;
+ case BUILT_IN_NORMAL:
+ break;
+ case BUILT_IN_MD:
+ if (targetm.resolve_overloaded_builtin)
+ return targetm.resolve_overloaded_builtin (function, params);
+ else
+ return NULL_TREE;
+ default:
return NULL_TREE;
}
- if (*t == x)
- return *t;
- return NULL_TREE;
-}
-/* Find out if a variable is uninitialized based on DECL_INITIAL. */
+ /* Handle BUILT_IN_NORMAL here. */
+ switch (orig_code)
+ {
+ case BUILT_IN_FETCH_AND_ADD_N:
+ case BUILT_IN_FETCH_AND_SUB_N:
+ case BUILT_IN_FETCH_AND_OR_N:
+ case BUILT_IN_FETCH_AND_AND_N:
+ case BUILT_IN_FETCH_AND_XOR_N:
+ case BUILT_IN_FETCH_AND_NAND_N:
+ case BUILT_IN_ADD_AND_FETCH_N:
+ case BUILT_IN_SUB_AND_FETCH_N:
+ case BUILT_IN_OR_AND_FETCH_N:
+ case BUILT_IN_AND_AND_FETCH_N:
+ case BUILT_IN_XOR_AND_FETCH_N:
+ case BUILT_IN_NAND_AND_FETCH_N:
+ case BUILT_IN_BOOL_COMPARE_AND_SWAP_N:
+ case BUILT_IN_VAL_COMPARE_AND_SWAP_N:
+ case BUILT_IN_LOCK_TEST_AND_SET_N:
+ case BUILT_IN_LOCK_RELEASE_N:
+ {
+ int n = sync_resolve_size (function, params);
+ tree new_function, result;
+
+ if (n == 0)
+ return error_mark_node;
+
+ new_function = built_in_decls[orig_code + exact_log2 (n) + 1];
+ if (!sync_resolve_params (function, new_function, params))
+ return error_mark_node;
+ result = build_function_call (new_function, params);
+ if (orig_code != BUILT_IN_BOOL_COMPARE_AND_SWAP_N
+ && orig_code != BUILT_IN_LOCK_RELEASE_N)
+ result = sync_resolve_return (params, result);
+
+ return result;
+ }
+
+ default:
+ return NULL_TREE;
+ }
+}
+
+/* Ignoring their sign, return true if two scalar types are the same. */
bool
-c_decl_uninit (tree t)
+same_scalar_type_ignoring_signedness (tree t1, tree t2)
{
- /* int x = x; is GCC extension to turn off this warning, only if warn_init_self is zero. */
- if (DECL_INITIAL (t) == t)
- return warn_init_self ? true : false;
+ enum tree_code c1 = TREE_CODE (t1), c2 = TREE_CODE (t2);
- /* Walk the trees looking for the variable itself. */
- if (walk_tree_without_duplicates (&DECL_INITIAL (t), c_decl_uninit_1, t))
- return true;
- return false;
+ gcc_assert ((c1 == INTEGER_TYPE || c1 == REAL_TYPE)
+ && (c2 == INTEGER_TYPE || c2 == REAL_TYPE));
+
+ /* Equality works here because c_common_signed_type uses
+ TYPE_MAIN_VARIANT. */
+ return lang_hooks.types.signed_type (t1)
+ == lang_hooks.types.signed_type (t2);
}
-/* Issue the error given by MSGID, indicating that it occurred before
- TOKEN, which had the associated VALUE. */
+/* Check for missing format attributes on function pointers. LTYPE is
+ the new type or left-hand side type. RTYPE is the old type or
+ right-hand side type. Returns TRUE if LTYPE is missing the desired
+ attribute. */
-void
-c_parse_error (const char *msgid, enum cpp_ttype token, tree value)
+bool
+check_missing_format_attribute (tree ltype, tree rtype)
{
- const char *string = _(msgid);
+ tree const ttr = TREE_TYPE (rtype), ttl = TREE_TYPE (ltype);
+ tree ra;
- if (token == CPP_EOF)
- error ("%s at end of input", string);
- else if (token == CPP_CHAR || token == CPP_WCHAR)
+ for (ra = TYPE_ATTRIBUTES (ttr); ra; ra = TREE_CHAIN (ra))
+ if (is_attribute_p ("format", TREE_PURPOSE (ra)))
+ break;
+ if (ra)
{
- unsigned int val = TREE_INT_CST_LOW (value);
- const char *const ell = (token == CPP_CHAR) ? "" : "L";
- if (val <= UCHAR_MAX && ISGRAPH (val))
- error ("%s before %s'%c'", string, ell, val);
- else
- error ("%s before %s'\\x%x'", string, ell, val);
+ tree la;
+ for (la = TYPE_ATTRIBUTES (ttl); la; la = TREE_CHAIN (la))
+ if (is_attribute_p ("format", TREE_PURPOSE (la)))
+ break;
+ return !la;
}
- else if (token == CPP_STRING
- || token == CPP_WSTRING)
- error ("%s before string constant", string);
- else if (token == CPP_NUMBER)
- error ("%s before numeric constant", string);
- else if (token == CPP_NAME)
- error ("%s before \"%s\"", string, IDENTIFIER_POINTER (value));
- else if (token < N_TTYPES)
- error ("%s before '%s' token", string, cpp_type2name (token));
else
- error ("%s", string);
+ return false;
}
+/* Subscripting with type char is likely to lose on a machine where
+ chars are signed. So warn on any machine, but optionally. Don't
+ warn for unsigned char since that type is safe. Don't warn for
+ signed char because anyone who uses that must have done so
+ deliberately. Furthermore, we reduce the false positive load by
+ warning only for non-constant value of type char. */
+
+void
+warn_array_subscript_with_type_char (tree index)
+{
+ if (TYPE_MAIN_VARIANT (TREE_TYPE (index)) == char_type_node
+ && TREE_CODE (index) != INTEGER_CST)
+ warning (OPT_Wchar_subscripts, "array subscript has type %<char%>");
+}
+
+
#include "gt-c-common.h"
OpenPOWER on IntegriCloud