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.c3549
1 files changed, 2953 insertions, 596 deletions
diff --git a/contrib/gcc/c-common.c b/contrib/gcc/c-common.c
index 3511f15..b40a35a 100644
--- a/contrib/gcc/c-common.c
+++ b/contrib/gcc/c-common.c
@@ -22,6 +22,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
#include "config.h"
#include "system.h"
#include "tree.h"
+#include "real.h"
#include "flags.h"
#include "toplev.h"
#include "output.h"
@@ -30,17 +31,17 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
#include "ggc.h"
#include "expr.h"
#include "c-common.h"
-#include "tree-inline.h"
#include "diagnostic.h"
#include "tm_p.h"
#include "obstack.h"
-#include "c-lex.h"
#include "cpplib.h"
#include "target.h"
-cpp_reader *parse_in; /* Declared in c-lex.h. */
+#include "langhooks.h"
+#include "except.h" /* For USING_SJLJ_EXCEPTIONS. */
+#include "tree-inline.h"
+#include "c-tree.h"
-#undef WCHAR_TYPE_SIZE
-#define WCHAR_TYPE_SIZE TYPE_PRECISION (wchar_type_node)
+cpp_reader *parse_in; /* Declared in c-pragma.h. */
/* We let tm.h override the types used here, to handle trivial differences
such as the choice of unsigned int or long unsigned int for size_t.
@@ -56,6 +57,10 @@ cpp_reader *parse_in; /* Declared in c-lex.h. */
#define WCHAR_TYPE "int"
#endif
+/* WCHAR_TYPE gets overridden by -fshort-wchar. */
+#define MODIFIED_WCHAR_TYPE \
+ (flag_short_wchar ? "short unsigned int" : WCHAR_TYPE)
+
#ifndef PTRDIFF_TYPE
#define PTRDIFF_TYPE "long int"
#endif
@@ -80,6 +85,10 @@ cpp_reader *parse_in; /* Declared in c-lex.h. */
: "long long unsigned int"))
#endif
+#ifndef REGISTER_PREFIX
+#define REGISTER_PREFIX ""
+#endif
+
/* The variant of the C language being processed. */
enum c_language_kind c_language;
@@ -180,6 +189,22 @@ enum c_language_kind c_language;
tree c_global_trees[CTI_MAX];
+/* Switches common to the C front ends. */
+
+/* Nonzero if prepreprocessing only. */
+int flag_preprocess_only;
+
+/* Nonzero if an ISO standard was selected. It rejects macros in the
+ user's namespace. */
+int flag_iso;
+
+/* Nonzero whenever Objective-C functionality is being used. */
+int flag_objc;
+
+/* Nonzero if -undef was given. It suppresses target built-in macros
+ and assertions. */
+int flag_undef;
+
/* Nonzero means don't recognize the non-ANSI builtin functions. */
int flag_no_builtin;
@@ -197,6 +222,180 @@ int flag_short_double;
int flag_short_wchar;
+/* Nonzero means allow Microsoft extensions without warnings or errors. */
+int flag_ms_extensions;
+
+/* Nonzero means don't recognize the keyword `asm'. */
+
+int flag_no_asm;
+
+/* Nonzero means give string constants the type `const char *', as mandated
+ by the standard. */
+
+int flag_const_strings;
+
+/* Nonzero means `$' can be in an identifier. */
+
+#ifndef DOLLARS_IN_IDENTIFIERS
+#define DOLLARS_IN_IDENTIFIERS 1
+#endif
+int dollars_in_ident = DOLLARS_IN_IDENTIFIERS;
+
+/* 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 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. */
+
+int warn_sign_compare;
+
+/* 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. */
+
+int warn_unknown_pragmas; /* Tri state variable. */
+
+/* Warn about format/argument anomalies in calls to formatted I/O functions
+ (*printf, *scanf, strftime, strfmon, etc.). */
+
+int warn_format;
+
+/* Warn about Y2K problems with strftime formats. */
+
+int warn_format_y2k;
+
+/* Warn about excess arguments to formats. */
+
+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;
+
+
+/* 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'. */
+
+int flag_cond_mismatch;
+
+/* Nonzero means enable C89 Amendment 1 features. */
+
+int flag_isoc94;
+
+/* Nonzero means use the ISO C99 dialect of C. */
+
+int flag_isoc99;
+
+/* Nonzero means that we have builtin functions, and main is an int */
+
+int flag_hosted = 1;
+
+/* Nonzero means add default format_arg attributes for functions not
+ in ISO C. */
+
+int flag_noniso_default_format_attributes = 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 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;
@@ -204,6 +403,254 @@ int warn_sequence_point;
/* 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;
+
+
+/* ObjC language option variables. */
+
+
+/* Open and close the file for outputting class declarations, if
+ requested (ObjC). */
+
+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. */
+
+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. */
+
+
+/* Nonzero means don't recognize any extension keywords. */
+
+int flag_no_gnu_keywords;
+
+/* Nonzero means do emit exported implementations of functions even if
+ they can be inlined. */
+
+int flag_implement_inlines = 1;
+
+/* Nonzero means do emit exported implementations of templates, instead of
+ multiple static copies in each file that needs a definition. */
+
+int flag_external_templates;
+
+/* Nonzero means that the decision to emit or not emit the implementation of a
+ template depends on where the template is instantiated, rather than where
+ it is defined. */
+
+int flag_alt_external_templates;
+
+/* Nonzero means that implicit instantiations will be emitted if needed. */
+
+int flag_implicit_templates = 1;
+
+/* Nonzero means that implicit instantiations of inline templates will be
+ emitted if needed, even if instantiations of non-inline templates
+ aren't. */
+
+int flag_implicit_inline_templates = 1;
+
+/* Nonzero means generate separate instantiation control files and
+ juggle them at link time. */
+
+int flag_use_repository;
+
+/* Nonzero if we want to issue diagnostics that the standard says are not
+ required. */
+
+int flag_optional_diags = 1;
+
+/* Nonzero means we should attempt to elide constructors when possible. */
+
+int flag_elide_constructors = 1;
+
+/* Nonzero means that member functions defined in class scope are
+ inline by default. */
+
+int flag_default_inline = 1;
+
+/* Controls whether compiler generates 'type descriptor' that give
+ run-time type information. */
+
+int flag_rtti = 1;
+
+/* Nonzero if we want to conserve space in the .o files. We do this
+ by putting uninitialized data and runtime initialized data into
+ .common instead of .data at the expense of not flagging multiple
+ definitions. */
+
+int flag_conserve_space;
+
+/* Nonzero if we want to obey access control semantics. */
+
+int flag_access_control = 1;
+
+/* Nonzero if we want to check the return value of new and avoid calling
+ constructors if it is a null pointer. */
+
+int flag_check_new;
+
+/* Nonzero if we want the new ISO rules for pushing a new scope for `for'
+ initialization variables.
+ 0: Old rules, set by -fno-for-scope.
+ 2: New ISO rules, set by -ffor-scope.
+ 1: Try to implement new ISO rules, but with backup compatibility
+ (and warnings). This is the default, for now. */
+
+int flag_new_for_scope = 1;
+
+/* Nonzero if we want to emit defined symbols with common-like linkage as
+ weak symbols where possible, in order to conform to C++ semantics.
+ Otherwise, emit them as local symbols. */
+
+int flag_weak = 1;
+
+/* Nonzero to use __cxa_atexit, rather than atexit, to register
+ destructors for local statics and global objects. */
+
+int flag_use_cxa_atexit = DEFAULT_USE_CXA_ATEXIT;
+
+/* Nonzero means output .vtable_{entry,inherit} for use in doing vtable gc. */
+
+int flag_vtable_gc;
+
+/* Nonzero means make the default pedwarns warnings instead of errors.
+ The value of this flag is ignored if -pedantic is specified. */
+
+int flag_permissive;
+
+/* Nonzero means to implement standard semantics for exception
+ specifications, calling unexpected if an exception is thrown that
+ doesn't match the specification. Zero means to treat them as
+ assertions and optimize accordingly, but not check them. */
+
+int flag_enforce_eh_specs = 1;
+
+/* The version of the C++ ABI in use. The following values are
+ allowed:
+
+ 0: The version of the ABI believed most conformant with the
+ C++ ABI specification. This ABI may change as bugs are
+ discovered and fixed. Therefore, 0 will not necessarily
+ indicate the same ABI in different versions of G++.
+
+ 1: The version of the ABI first used in G++ 3.2.
+
+ Additional positive integers will be assigned as new versions of
+ the ABI become the default version of the ABI. */
+
+int flag_abi_version = 1;
+
+/* Nonzero means warn about things that will change when compiling
+ with an ABI-compliant compiler. */
+
+int warn_abi = 0;
+
+/* 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 = 1;
+
+/* 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. */
+
+int max_tinst_depth = 500;
+
+
+
/* The elements of `ridpointers' are identifier nodes for the reserved
type names and storage classes. It is indexed by a RID_... value. */
tree *ridpointers;
@@ -267,6 +714,169 @@ static int if_stack_space = 0;
/* Stack pointer. */
static int if_stack_pointer = 0;
+static tree handle_packed_attribute PARAMS ((tree *, tree, tree, int,
+ bool *));
+static tree handle_nocommon_attribute PARAMS ((tree *, tree, tree, int,
+ bool *));
+static tree handle_common_attribute PARAMS ((tree *, tree, tree, int,
+ bool *));
+static tree handle_noreturn_attribute PARAMS ((tree *, tree, tree, int,
+ bool *));
+static tree handle_noinline_attribute PARAMS ((tree *, tree, tree, int,
+ bool *));
+static tree handle_always_inline_attribute PARAMS ((tree *, tree, tree, int,
+ bool *));
+static tree handle_used_attribute PARAMS ((tree *, tree, tree, int,
+ bool *));
+static tree handle_unused_attribute PARAMS ((tree *, tree, tree, int,
+ bool *));
+static tree handle_const_attribute PARAMS ((tree *, tree, tree, int,
+ bool *));
+static tree handle_transparent_union_attribute PARAMS ((tree *, tree, tree,
+ int, bool *));
+static tree handle_constructor_attribute PARAMS ((tree *, tree, tree, int,
+ bool *));
+static tree handle_destructor_attribute PARAMS ((tree *, tree, tree, int,
+ bool *));
+static tree handle_mode_attribute PARAMS ((tree *, tree, tree, int,
+ bool *));
+static tree handle_section_attribute PARAMS ((tree *, tree, tree, int,
+ bool *));
+static tree handle_aligned_attribute PARAMS ((tree *, tree, tree, int,
+ bool *));
+static tree handle_weak_attribute PARAMS ((tree *, tree, tree, int,
+ bool *));
+static tree handle_alias_attribute PARAMS ((tree *, tree, tree, int,
+ bool *));
+static tree handle_visibility_attribute PARAMS ((tree *, tree, tree, int,
+ bool *));
+static tree handle_tls_model_attribute PARAMS ((tree *, tree, tree, int,
+ bool *));
+static tree handle_no_instrument_function_attribute PARAMS ((tree *, tree,
+ tree, int,
+ bool *));
+static tree handle_malloc_attribute PARAMS ((tree *, tree, tree, int,
+ bool *));
+static tree handle_no_limit_stack_attribute PARAMS ((tree *, tree, tree, int,
+ bool *));
+static tree handle_pure_attribute PARAMS ((tree *, tree, tree, int,
+ bool *));
+static tree handle_deprecated_attribute PARAMS ((tree *, tree, tree, int,
+ bool *));
+static tree handle_vector_size_attribute PARAMS ((tree *, tree, tree, int,
+ bool *));
+static tree handle_nonnull_attribute PARAMS ((tree *, tree, tree, int,
+ bool *));
+static tree handle_nothrow_attribute PARAMS ((tree *, tree, tree, int,
+ bool *));
+static tree handle_cleanup_attribute PARAMS ((tree *, tree, tree, int,
+ bool *));
+static tree vector_size_helper PARAMS ((tree, tree));
+
+static void check_function_nonnull PARAMS ((tree, tree));
+static void check_nonnull_arg PARAMS ((void *, tree,
+ unsigned HOST_WIDE_INT));
+static bool nonnull_check_p PARAMS ((tree, unsigned HOST_WIDE_INT));
+static bool get_nonnull_operand PARAMS ((tree,
+ unsigned HOST_WIDE_INT *));
+void builtin_define_std PARAMS ((const char *));
+static void builtin_define_with_value PARAMS ((const char *, const char *,
+ int));
+static void builtin_define_with_int_value PARAMS ((const char *,
+ HOST_WIDE_INT));
+static void builtin_define_with_hex_fp_value PARAMS ((const char *, tree,
+ int, const char *,
+ const char *));
+static void builtin_define_type_max PARAMS ((const char *, tree, int));
+static void builtin_define_type_precision PARAMS ((const char *, tree));
+static void builtin_define_float_constants PARAMS ((const char *,
+ const char *, tree));
+
+/* Table of machine-independent attributes common to all C-like languages. */
+const struct attribute_spec c_common_attribute_table[] =
+{
+ /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */
+ { "packed", 0, 0, false, false, false,
+ handle_packed_attribute },
+ { "nocommon", 0, 0, true, false, false,
+ handle_nocommon_attribute },
+ { "common", 0, 0, true, false, false,
+ handle_common_attribute },
+ /* FIXME: logically, noreturn attributes should be listed as
+ "false, true, true" and apply to function types. But implementing this
+ would require all the places in the compiler that use TREE_THIS_VOLATILE
+ on a decl to identify non-returning functions to be located and fixed
+ to check the function type instead. */
+ { "noreturn", 0, 0, true, false, false,
+ handle_noreturn_attribute },
+ { "volatile", 0, 0, true, false, false,
+ handle_noreturn_attribute },
+ { "noinline", 0, 0, true, false, false,
+ handle_noinline_attribute },
+ { "always_inline", 0, 0, true, false, false,
+ handle_always_inline_attribute },
+ { "used", 0, 0, true, false, false,
+ handle_used_attribute },
+ { "unused", 0, 0, false, false, false,
+ handle_unused_attribute },
+ /* The same comments as for noreturn attributes apply to const ones. */
+ { "const", 0, 0, true, false, false,
+ handle_const_attribute },
+ { "transparent_union", 0, 0, false, false, false,
+ handle_transparent_union_attribute },
+ { "constructor", 0, 0, true, false, false,
+ handle_constructor_attribute },
+ { "destructor", 0, 0, true, false, false,
+ handle_destructor_attribute },
+ { "mode", 1, 1, false, true, false,
+ handle_mode_attribute },
+ { "section", 1, 1, true, false, false,
+ handle_section_attribute },
+ { "aligned", 0, 1, false, false, false,
+ handle_aligned_attribute },
+ { "weak", 0, 0, true, false, false,
+ handle_weak_attribute },
+ { "alias", 1, 1, true, false, false,
+ handle_alias_attribute },
+ { "no_instrument_function", 0, 0, true, false, false,
+ handle_no_instrument_function_attribute },
+ { "malloc", 0, 0, true, false, false,
+ handle_malloc_attribute },
+ { "no_stack_limit", 0, 0, true, false, false,
+ handle_no_limit_stack_attribute },
+ { "pure", 0, 0, true, false, false,
+ handle_pure_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,
+ handle_visibility_attribute },
+ { "tls_model", 1, 1, true, false, false,
+ handle_tls_model_attribute },
+ { "nonnull", 0, -1, false, true, true,
+ handle_nonnull_attribute },
+ { "nothrow", 0, 0, true, false, false,
+ handle_nothrow_attribute },
+ { "may_alias", 0, 0, false, true, false, NULL },
+ { "cleanup", 1, 1, true, false, false,
+ handle_cleanup_attribute },
+ { NULL, 0, 0, false, false, false, NULL }
+};
+
+/* Give the specifications for the format attributes, used by C and all
+ descendents. */
+
+const struct attribute_spec c_common_format_attribute_table[] =
+{
+ /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */
+ { "format", 3, 3, false, true, true,
+ handle_format_attribute },
+ { "format_arg", 1, 1, false, true, true,
+ handle_format_arg_attribute },
+ { NULL, 0, 0, false, false, false, NULL }
+};
+
/* Record the start of an if-then, and record the start of it
for ambiguous else detection.
@@ -483,7 +1093,7 @@ fname_as_string (pretty_p)
if (pretty_p)
name = (current_function_decl
- ? (*decl_printable_name) (current_function_decl, 2)
+ ? (*lang_hooks.decl_printable_name) (current_function_decl, 2)
: "top level");
else if (current_function_decl && DECL_NAME (current_function_decl))
name = IDENTIFIER_POINTER (DECL_NAME (current_function_decl));
@@ -530,6 +1140,13 @@ fname_decl (rid, id)
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 = lineno;
+ lineno = 0;
decl = (*make_fname_decl) (id, fname_vars[ix].pretty);
if (last_tree != saved_last_tree)
@@ -545,6 +1162,7 @@ fname_decl (rid, id)
saved_function_name_decls);
}
*fname_vars[ix].decl = decl;
+ lineno = saved_lineno;
}
if (!ix && !current_function_decl)
pedwarn_with_decl (decl, "`%s' is not defined outside of function scope");
@@ -552,136 +1170,152 @@ fname_decl (rid, id)
return decl;
}
-/* Given a chain of STRING_CST nodes,
- concatenate them into one STRING_CST
- and give it a suitable array-of-chars data type. */
+/* Given a STRING_CST, give it a suitable array-of-chars data type. */
+
+tree
+fix_string_type (value)
+ 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;
+
+ /* Compute the number of elements, for the array type. */
+ nchars = wide_flag ? length / wchar_bytes : length;
+
+ if (pedantic && nchars - 1 > nchars_max && c_language == clk_c)
+ 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)));
+
+ TREE_CONSTANT (value) = 1;
+ TREE_READONLY (value) = ! flag_writable_strings;
+ TREE_STATIC (value) = 1;
+ return value;
+}
+
+/* Given a VARRAY of STRING_CST nodes, concatenate them into one
+ STRING_CST. */
tree
combine_strings (strings)
- tree strings;
+ varray_type strings;
{
+ const int wchar_bytes = TYPE_PRECISION (wchar_type_node) / BITS_PER_UNIT;
+ const int nstrings = VARRAY_ACTIVE_SIZE (strings);
tree value, t;
int length = 1;
int wide_length = 0;
int wide_flag = 0;
- int wchar_bytes = TYPE_PRECISION (wchar_type_node) / BITS_PER_UNIT;
- int nchars;
- const int nchars_max = flag_isoc99 ? 4095 : 509;
+ int i;
+ char *p, *q;
- if (TREE_CHAIN (strings))
+ /* Don't include the \0 at the end of each substring. Count wide
+ strings and ordinary strings separately. */
+ for (i = 0; i < nstrings; ++i)
{
- /* More than one in the chain, so concatenate. */
- char *p, *q;
+ t = VARRAY_TREE (strings, i);
- /* Don't include the \0 at the end of each substring,
- except for the last one.
- Count wide strings and ordinary strings separately. */
- for (t = strings; t; t = TREE_CHAIN (t))
+ if (TREE_TYPE (t) == wchar_array_type_node)
{
- if (TREE_TYPE (t) == wchar_array_type_node)
- {
- wide_length += (TREE_STRING_LENGTH (t) - wchar_bytes);
- wide_flag = 1;
- }
- else
- {
- length += (TREE_STRING_LENGTH (t) - 1);
- if (C_ARTIFICIAL_STRING_P (t) && !in_system_header)
- warning ("concatenation of string literals with __FUNCTION__ is deprecated");
- }
+ wide_length += TREE_STRING_LENGTH (t) - wchar_bytes;
+ wide_flag = 1;
+ }
+ else
+ {
+ length += (TREE_STRING_LENGTH (t) - 1);
+ if (C_ARTIFICIAL_STRING_P (t) && !in_system_header)
+ warning ("concatenation of string literals with __FUNCTION__ is deprecated");
}
+ }
+
+ /* If anything is wide, the non-wides will be converted,
+ which makes them take more space. */
+ if (wide_flag)
+ length = length * wchar_bytes + wide_length;
- /* If anything is wide, the non-wides will be converted,
- which makes them take more space. */
- if (wide_flag)
- length = length * wchar_bytes + wide_length;
+ p = xmalloc (length);
- p = xmalloc (length);
+ /* Copy the individual strings into the new combined string.
+ If the combined string is wide, convert the chars to ints
+ for any individual strings that are not wide. */
- /* Copy the individual strings into the new combined string.
- If the combined string is wide, convert the chars to ints
- for any individual strings that are not wide. */
+ q = p;
+ for (i = 0; i < nstrings; ++i)
+ {
+ int len, this_wide;
- q = p;
- for (t = strings; t; t = TREE_CHAIN (t))
+ t = VARRAY_TREE (strings, i);
+ this_wide = TREE_TYPE (t) == wchar_array_type_node;
+ len = TREE_STRING_LENGTH (t) - (this_wide ? wchar_bytes : 1);
+ if (this_wide == wide_flag)
{
- int len = (TREE_STRING_LENGTH (t)
- - ((TREE_TYPE (t) == wchar_array_type_node)
- ? wchar_bytes : 1));
- if ((TREE_TYPE (t) == wchar_array_type_node) == wide_flag)
+ memcpy (q, TREE_STRING_POINTER (t), len);
+ q += len;
+ }
+ else
+ {
+ const int nzeros = (TYPE_PRECISION (wchar_type_node)
+ / BITS_PER_UNIT) - 1;
+ int j, k;
+
+ if (BYTES_BIG_ENDIAN)
{
- memcpy (q, TREE_STRING_POINTER (t), len);
- q += len;
+ for (k = 0; k < len; k++)
+ {
+ for (j = 0; j < nzeros; j++)
+ *q++ = 0;
+ *q++ = TREE_STRING_POINTER (t)[k];
+ }
}
else
{
- int i, j;
- for (i = 0; i < len; i++)
+ for (k = 0; k < len; k++)
{
- if (BYTES_BIG_ENDIAN)
- {
- for (j=0; j<(WCHAR_TYPE_SIZE / BITS_PER_UNIT)-1; j++)
- *q++ = 0;
- *q++ = TREE_STRING_POINTER (t)[i];
- }
- else
- {
- *q++ = TREE_STRING_POINTER (t)[i];
- for (j=0; j<(WCHAR_TYPE_SIZE / BITS_PER_UNIT)-1; j++)
- *q++ = 0;
- }
+ *q++ = TREE_STRING_POINTER (t)[k];
+ for (j = 0; j < nzeros; j++)
+ *q++ = 0;
}
}
}
- if (wide_flag)
- {
- int i;
- for (i = 0; i < wchar_bytes; i++)
- *q++ = 0;
- }
- else
- *q = 0;
-
- value = build_string (length, p);
- free (p);
}
- else
+
+ /* Nul terminate the string. */
+ if (wide_flag)
{
- value = strings;
- length = TREE_STRING_LENGTH (value);
- if (TREE_TYPE (value) == wchar_array_type_node)
- wide_flag = 1;
+ for (i = 0; i < wchar_bytes; i++)
+ *q++ = 0;
}
+ else
+ *q = 0;
- /* Compute the number of elements, for the array type. */
- nchars = wide_flag ? length / wchar_bytes : length;
-
- if (pedantic && nchars - 1 > nchars_max && c_language == clk_c)
- 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);
+ value = build_string (length, p);
+ free (p);
- /* Create the array type for the string constant.
- -Wwrite-strings says make the string constant an array of const char
- so that copying it to a non-const pointer will get a warning.
- For C++, this is the standard behavior. */
- if (flag_const_strings
- && (! flag_traditional && ! flag_writable_strings))
- {
- tree elements
- = build_type_variant (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)));
- }
+ if (wide_flag)
+ TREE_TYPE (value) = wchar_array_type_node;
else
- TREE_TYPE (value)
- = build_array_type (wide_flag ? wchar_type_node : char_type_node,
- build_index_type (build_int_2 (nchars - 1, 0)));
+ TREE_TYPE (value) = char_array_type_node;
- TREE_CONSTANT (value) = 1;
- TREE_READONLY (value) = ! flag_writable_strings;
- TREE_STATIC (value) = 1;
return value;
}
@@ -755,13 +1389,15 @@ void
unsigned_conversion_warning (result, operand)
tree result, operand;
{
+ tree type = TREE_TYPE (result);
+
if (TREE_CODE (operand) == INTEGER_CST
- && TREE_CODE (TREE_TYPE (result)) == INTEGER_TYPE
- && TREE_UNSIGNED (TREE_TYPE (result))
+ && TREE_CODE (type) == INTEGER_TYPE
+ && TREE_UNSIGNED (type)
&& skip_evaluation == 0
- && !int_fits_type_p (operand, TREE_TYPE (result)))
+ && !int_fits_type_p (operand, type))
{
- if (!int_fits_type_p (operand, signed_type (TREE_TYPE (result))))
+ 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)
@@ -810,7 +1446,8 @@ convert_and_check (type, expr)
don't warn unless pedantic. */
if ((pedantic
|| TREE_UNSIGNED (type)
- || ! constant_fits_type_p (expr, unsigned_type (type)))
+ || ! constant_fits_type_p (expr,
+ c_common_unsigned_type (type)))
&& skip_evaluation == 0)
warning ("overflow in implicit constant conversion");
}
@@ -1212,7 +1849,7 @@ verify_tree (x, pbefore_sp, pno_sp, writer)
}
}
-/* Try to warn for undefined behaviour in EXPR due to missing sequence
+/* Try to warn for undefined behavior in EXPR due to missing sequence
points. */
static void
@@ -1300,7 +1937,7 @@ check_case_value (value)
that is unsigned if UNSIGNEDP is nonzero, otherwise signed. */
tree
-type_for_size (bits, unsignedp)
+c_common_type_for_size (bits, unsignedp)
unsigned bits;
int unsignedp;
{
@@ -1344,7 +1981,7 @@ type_for_size (bits, unsignedp)
then UNSIGNEDP selects between signed and unsigned types. */
tree
-type_for_mode (mode, unsignedp)
+c_common_type_for_mode (mode, unsignedp)
enum machine_mode mode;
int unsignedp;
{
@@ -1399,41 +2036,44 @@ type_for_mode (mode, unsignedp)
if (mode == TYPE_MODE (build_pointer_type (integer_type_node)))
return build_pointer_type (integer_type_node);
-#ifdef VECTOR_MODE_SUPPORTED_P
- if (VECTOR_MODE_SUPPORTED_P (mode))
+ switch (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 V2SImode:
- return unsignedp ? unsigned_V2SI_type_node : V2SI_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 V16SFmode:
- return V16SF_type_node;
- case V4SFmode:
- return V4SF_type_node;
- case V2SFmode:
- return V2SF_type_node;
- default:
- break;
- }
+ 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;
+ default:
+ break;
}
-#endif
return 0;
}
/* Return an unsigned type the same as TYPE in other respects. */
tree
-unsigned_type (type)
+c_common_unsigned_type (type)
tree type;
{
tree type1 = TYPE_MAIN_VARIANT (type);
@@ -1462,13 +2102,13 @@ unsigned_type (type)
if (type1 == intQI_type_node)
return unsigned_intQI_type_node;
- return signed_or_unsigned_type (1, type);
+ return c_common_signed_or_unsigned_type (1, type);
}
/* Return a signed type the same as TYPE in other respects. */
tree
-signed_type (type)
+c_common_signed_type (type)
tree type;
{
tree type1 = TYPE_MAIN_VARIANT (type);
@@ -1497,14 +2137,14 @@ signed_type (type)
if (type1 == unsigned_intQI_type_node)
return intQI_type_node;
- return signed_or_unsigned_type (0, type);
+ return c_common_signed_or_unsigned_type (0, type);
}
/* Return a type the same as TYPE except unsigned or
signed according to UNSIGNEDP. */
tree
-signed_or_unsigned_type (unsignedp, type)
+c_common_signed_or_unsigned_type (unsignedp, type)
int unsignedp;
tree type;
{
@@ -1572,8 +2212,9 @@ min_precision (value, 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 truthvalue_conversion). */
+/* Print an error message for invalid operands to arith operation
+ CODE. NOP_EXPR is used as a special case (see
+ c_common_truthvalue_conversion). */
void
binary_op_error (code)
@@ -1753,19 +2394,20 @@ shorten_compare (op0_ptr, op1_ptr, restype_ptr, rescode_ptr)
int unsignedp = TREE_UNSIGNED (*restype_ptr);
tree val;
- type = signed_or_unsigned_type (unsignedp0, TREE_TYPE (primop0));
+ type = c_common_signed_or_unsigned_type (unsignedp0,
+ TREE_TYPE (primop0));
/* If TYPE is an enumeration, then we need to get its min/max
values from it's underlying integral type, not the enumerated
type itself. */
if (TREE_CODE (type) == ENUMERAL_TYPE)
- type = type_for_size (TYPE_PRECISION (type), unsignedp0);
+ type = c_common_type_for_size (TYPE_PRECISION (type), unsignedp0);
maxval = TYPE_MAX_VALUE (type);
minval = TYPE_MIN_VALUE (type);
if (unsignedp && !unsignedp0)
- *restype_ptr = signed_type (*restype_ptr);
+ *restype_ptr = c_common_signed_type (*restype_ptr);
if (TREE_TYPE (primop1) != *restype_ptr)
primop1 = convert (*restype_ptr, primop1);
@@ -1862,22 +2504,11 @@ shorten_compare (op0_ptr, op1_ptr, restype_ptr, rescode_ptr)
default:
break;
}
- type = unsigned_type (type);
- }
-
- if (!max_gt && !unsignedp0 && TREE_CODE (primop0) != INTEGER_CST)
- {
- /* This is the case of (char)x >?< 0x80, which people used to use
- expecting old C compilers to change the 0x80 into -0x80. */
- if (val == boolean_false_node)
- warning ("comparison is always false due to limited range of data type");
- if (val == boolean_true_node)
- warning ("comparison is always true due to limited range of data type");
+ type = c_common_unsigned_type (type);
}
- if (!min_lt && unsignedp0 && TREE_CODE (primop0) != INTEGER_CST)
+ if (TREE_CODE (primop0) != INTEGER_CST)
{
- /* This is the case of (unsigned char)x >?< -1 or < 0. */
if (val == boolean_false_node)
warning ("comparison is always false due to limited range of data type");
if (val == boolean_true_node)
@@ -1914,15 +2545,19 @@ shorten_compare (op0_ptr, op1_ptr, restype_ptr, rescode_ptr)
&& TYPE_PRECISION (TREE_TYPE (primop1)) < TYPE_PRECISION (*restype_ptr))
{
type = common_type (TREE_TYPE (primop0), TREE_TYPE (primop1));
- type = signed_or_unsigned_type (unsignedp0
- || TREE_UNSIGNED (*restype_ptr),
- type);
+ type = c_common_signed_or_unsigned_type (unsignedp0
+ || TREE_UNSIGNED (*restype_ptr),
+ type);
/* Make sure shorter operand is extended the right way
to match the longer operand. */
- primop0 = convert (signed_or_unsigned_type (unsignedp0, TREE_TYPE (primop0)),
- primop0);
- primop1 = convert (signed_or_unsigned_type (unsignedp1, TREE_TYPE (primop1)),
- primop1);
+ primop0
+ = convert (c_common_signed_or_unsigned_type (unsignedp0,
+ TREE_TYPE (primop0)),
+ primop0);
+ primop1
+ = convert (c_common_signed_or_unsigned_type (unsignedp1,
+ TREE_TYPE (primop1)),
+ primop1);
}
else
{
@@ -1945,7 +2580,7 @@ shorten_compare (op0_ptr, op1_ptr, restype_ptr, rescode_ptr)
so suppress the warning. */
if (extra_warnings && !in_system_header
&& ! (TREE_CODE (primop0) == INTEGER_CST
- && ! TREE_OVERFLOW (convert (signed_type (type),
+ && ! TREE_OVERFLOW (convert (c_common_signed_type (type),
primop0))))
warning ("comparison of unsigned expression >= 0 is always true");
value = boolean_true_node;
@@ -1954,7 +2589,7 @@ shorten_compare (op0_ptr, op1_ptr, restype_ptr, rescode_ptr)
case LT_EXPR:
if (extra_warnings && !in_system_header
&& ! (TREE_CODE (primop0) == INTEGER_CST
- && ! TREE_OVERFLOW (convert (signed_type (type),
+ && ! TREE_OVERFLOW (convert (c_common_signed_type (type),
primop0))))
warning ("comparison of unsigned expression < 0 is always false");
value = boolean_false_node;
@@ -2063,8 +2698,8 @@ pointer_int_sum (resultcode, ptrop, intop)
if (TYPE_PRECISION (TREE_TYPE (intop)) != TYPE_PRECISION (sizetype)
|| TREE_UNSIGNED (TREE_TYPE (intop)) != TREE_UNSIGNED (sizetype))
- intop = convert (type_for_size (TYPE_PRECISION (sizetype),
- TREE_UNSIGNED (sizetype)), intop);
+ intop = convert (c_common_type_for_size (TYPE_PRECISION (sizetype),
+ TREE_UNSIGNED (sizetype)), intop);
/* Replace the integer argument with a suitable product by the object size.
Do this multiplication as signed, then convert to the appropriate
@@ -2096,7 +2731,7 @@ pointer_int_sum (resultcode, ptrop, intop)
The resulting type should always be `boolean_type_node'. */
tree
-truthvalue_conversion (expr)
+c_common_truthvalue_conversion (expr)
tree expr;
{
if (TREE_CODE (expr) == ERROR_MARK)
@@ -2162,32 +2797,32 @@ truthvalue_conversion (expr)
case COMPLEX_EXPR:
return build_binary_op ((TREE_SIDE_EFFECTS (TREE_OPERAND (expr, 1))
? TRUTH_OR_EXPR : TRUTH_ORIF_EXPR),
- truthvalue_conversion (TREE_OPERAND (expr, 0)),
- truthvalue_conversion (TREE_OPERAND (expr, 1)),
+ c_common_truthvalue_conversion (TREE_OPERAND (expr, 0)),
+ c_common_truthvalue_conversion (TREE_OPERAND (expr, 1)),
0);
case NEGATE_EXPR:
case ABS_EXPR:
case FLOAT_EXPR:
case FFS_EXPR:
- /* These don't change whether an object is non-zero or zero. */
- return truthvalue_conversion (TREE_OPERAND (expr, 0));
+ /* These don't change whether an object is nonzero or zero. */
+ return c_common_truthvalue_conversion (TREE_OPERAND (expr, 0));
case LROTATE_EXPR:
case RROTATE_EXPR:
- /* These don't change whether an object is zero or non-zero, but
+ /* 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, boolean_type_node, TREE_OPERAND (expr, 1),
- truthvalue_conversion (TREE_OPERAND (expr, 0)));
+ c_common_truthvalue_conversion (TREE_OPERAND (expr, 0)));
else
- return truthvalue_conversion (TREE_OPERAND (expr, 0));
+ 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, boolean_type_node, TREE_OPERAND (expr, 0),
- truthvalue_conversion (TREE_OPERAND (expr, 1)),
- truthvalue_conversion (TREE_OPERAND (expr, 2))));
+ c_common_truthvalue_conversion (TREE_OPERAND (expr, 1)),
+ c_common_truthvalue_conversion (TREE_OPERAND (expr, 2))));
case CONVERT_EXPR:
/* Don't cancel the effect of a CONVERT_EXPR from a REFERENCE_TYPE,
@@ -2200,14 +2835,19 @@ truthvalue_conversion (expr)
/* If this is widening the argument, we can ignore it. */
if (TYPE_PRECISION (TREE_TYPE (expr))
>= TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (expr, 0))))
- return truthvalue_conversion (TREE_OPERAND (expr, 0));
+ return c_common_truthvalue_conversion (TREE_OPERAND (expr, 0));
break;
case MINUS_EXPR:
- /* With IEEE arithmetic, x - x may not equal 0, so we can't optimize
- this case. */
- if (TARGET_FLOAT_FORMAT == IEEE_FLOAT_FORMAT
- && TREE_CODE (TREE_TYPE (expr)) == REAL_TYPE)
+ /* 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:
@@ -2240,12 +2880,12 @@ truthvalue_conversion (expr)
if (TREE_CODE (TREE_TYPE (expr)) == COMPLEX_TYPE)
{
- tree tem = save_expr (expr);
+ tree t = save_expr (expr);
return (build_binary_op
((TREE_SIDE_EFFECTS (expr)
? TRUTH_OR_EXPR : TRUTH_ORIF_EXPR),
- truthvalue_conversion (build_unary_op (REALPART_EXPR, tem, 0)),
- truthvalue_conversion (build_unary_op (IMAGPART_EXPR, tem, 0)),
+ c_common_truthvalue_conversion (build_unary_op (REALPART_EXPR, t, 0)),
+ c_common_truthvalue_conversion (build_unary_op (IMAGPART_EXPR, t, 0)),
0));
}
@@ -2254,7 +2894,7 @@ truthvalue_conversion (expr)
static tree builtin_function_2 PARAMS ((const char *, const char *, tree, tree,
int, enum built_in_class, int, int,
- int));
+ tree));
/* Make a variant type in the proper way for C/C++, propagating qualifiers
down to the element type of an array. */
@@ -2316,7 +2956,6 @@ c_apply_type_quals_to_decl (type_quals, decl)
}
}
-
/* 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. */
@@ -2349,13 +2988,17 @@ c_common_get_alias_set (t)
|| t == signed_char_type_node
|| t == unsigned_char_type_node)
return 0;
-
+
+ /* If it has the may_alias attribute, it can alias anything. */
+ if (lookup_attribute ("may_alias", TYPE_ATTRIBUTES (t)))
+ return 0;
+
/* 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))
{
- tree t1 = signed_type (t);
+ tree t1 = c_common_signed_type (t);
/* t1 == t can happen for boolean nodes which are always unsigned. */
if (t1 != t)
@@ -2396,36 +3039,66 @@ c_common_get_alias_set (t)
return -1;
}
-/* Implement the __alignof keyword: Return the minimum required
- alignment of TYPE, measured in bytes. */
-
+/* Compute the value of 'sizeof (TYPE)' or '__alignof__ (TYPE)', where the
+ second parameter indicates which OPERATOR is being applied. The COMPLAIN
+ flag controls whether we should diagnose possibly ill-formed
+ constructs or not. */
tree
-c_alignof (type)
+c_sizeof_or_alignof_type (type, op, complain)
tree type;
+ enum tree_code op;
+ int complain;
{
- enum tree_code code = TREE_CODE (type);
- tree t;
-
- /* In C++, sizeof applies to the referent. Handle alignof the same way. */
- if (code == REFERENCE_TYPE)
+ 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__";
+
+ if (type_code == FUNCTION_TYPE)
{
- type = TREE_TYPE (type);
- code = TREE_CODE (type);
+ if (op == SIZEOF_EXPR)
+ {
+ if (complain && (pedantic || warn_pointer_arith))
+ pedwarn ("invalid application of `sizeof' to a function type");
+ value = size_one_node;
+ }
+ else
+ value = size_int (FUNCTION_BOUNDARY / BITS_PER_UNIT);
+ }
+ else if (type_code == VOID_TYPE || type_code == ERROR_MARK)
+ {
+ if (type_code == VOID_TYPE
+ && complain && (pedantic || warn_pointer_arith))
+ pedwarn ("invalid application of `%s' to a void type", op_name);
+ value = size_one_node;
}
-
- if (code == FUNCTION_TYPE)
- t = size_int (FUNCTION_BOUNDARY / BITS_PER_UNIT);
- else if (code == VOID_TYPE || code == ERROR_MARK)
- t = size_one_node;
else if (!COMPLETE_TYPE_P (type))
{
- error ("__alignof__ applied to an incomplete type");
- t = size_zero_node;
+ if (complain)
+ error ("invalid application of `%s' to an incomplete type", op_name);
+ value = size_zero_node;
}
else
- t = size_int (TYPE_ALIGN (type) / BITS_PER_UNIT);
+ {
+ if (op == SIZEOF_EXPR)
+ /* 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);
+ }
- return fold (build1 (NOP_EXPR, size_type_node, t));
+ /* 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);
+
+ return value;
}
/* Implement the __alignof keyword: Return the minimum required
@@ -2476,19 +3149,30 @@ c_alignof_expr (expr)
return fold (build1 (NOP_EXPR, size_type_node, t));
}
-/* Give the specifications for the format attributes, used by C and all
- descendents. */
+/* Handle C and C++ default attributes. */
-static const struct attribute_spec c_format_attribute_table[] =
+enum built_in_attribute
{
- /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */
- { "format", 3, 3, false, true, true,
- handle_format_attribute },
- { "format_arg", 1, 1, false, true, true,
- handle_format_arg_attribute },
- { NULL, 0, 0, false, false, false, NULL }
+#define DEF_ATTR_NULL_TREE(ENUM) ENUM,
+#define DEF_ATTR_INT(ENUM, VALUE) ENUM,
+#define DEF_ATTR_IDENT(ENUM, STRING) ENUM,
+#define DEF_ATTR_TREE_LIST(ENUM, PURPOSE, VALUE, CHAIN) ENUM,
+#define DEF_FN_ATTR(NAME, ATTRS, PREDICATE) /* No entry needed in enum. */
+#include "builtin-attrs.def"
+#undef DEF_ATTR_NULL_TREE
+#undef DEF_ATTR_INT
+#undef DEF_ATTR_IDENT
+#undef DEF_ATTR_TREE_LIST
+#undef DEF_FN_ATTR
+ ATTR_LAST
};
+static GTY(()) tree built_in_attributes[(int) ATTR_LAST];
+
+static bool c_attrs_initialized = false;
+
+static void c_init_attributes PARAMS ((void));
+
/* Build tree nodes and builtin functions common to both C and C++ language
frontends. */
@@ -2506,6 +3190,7 @@ c_common_nodes_and_builtins ()
#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_POINTER_TYPE(NAME, TYPE) NAME,
#include "builtin-types.def"
#undef DEF_PRIMITIVE_TYPE
@@ -2517,6 +3202,7 @@ c_common_nodes_and_builtins ()
#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_POINTER_TYPE
BT_LAST
};
@@ -2526,18 +3212,9 @@ c_common_nodes_and_builtins ()
tree builtin_types[(int) BT_LAST];
int wchar_type_size;
tree array_domain_type;
- /* Either char* or void*. */
- tree traditional_ptr_type_node;
- /* Either const char* or const void*. */
- tree traditional_cptr_type_node;
- tree traditional_len_type_node;
tree va_list_ref_type_node;
tree va_list_arg_type_node;
- /* We must initialize this before any builtin functions (which might have
- attributes) are declared. (c_common_init is too late.) */
- format_attribute_table = c_format_attribute_table;
-
/* Define `int' and `char' first so that dbx will output them first. */
record_builtin_type (RID_INT, NULL, integer_type_node);
record_builtin_type (RID_CHAR, "char", char_type_node);
@@ -2571,41 +3248,52 @@ c_common_nodes_and_builtins ()
record_builtin_type (RID_MAX, "signed char", signed_char_type_node);
record_builtin_type (RID_MAX, "unsigned char", unsigned_char_type_node);
- /* These are types that type_for_size and type_for_mode use. */
- pushdecl (build_decl (TYPE_DECL, NULL_TREE, intQI_type_node));
- pushdecl (build_decl (TYPE_DECL, NULL_TREE, intHI_type_node));
- pushdecl (build_decl (TYPE_DECL, NULL_TREE, intSI_type_node));
- pushdecl (build_decl (TYPE_DECL, NULL_TREE, intDI_type_node));
+ /* 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));
#if HOST_BITS_PER_WIDE_INT >= 64
- pushdecl (build_decl (TYPE_DECL, get_identifier ("__int128_t"), intTI_type_node));
+ (*lang_hooks.decls.pushdecl) (build_decl (TYPE_DECL,
+ get_identifier ("__int128_t"),
+ intTI_type_node));
#endif
- pushdecl (build_decl (TYPE_DECL, NULL_TREE, unsigned_intQI_type_node));
- pushdecl (build_decl (TYPE_DECL, NULL_TREE, unsigned_intHI_type_node));
- pushdecl (build_decl (TYPE_DECL, NULL_TREE, unsigned_intSI_type_node));
- 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
- pushdecl (build_decl (TYPE_DECL, get_identifier ("__uint128_t"), unsigned_intTI_type_node));
+ (*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);
- 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);
- 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',
and this must agree, even if long and int are the same size. */
size_type_node =
TREE_TYPE (identifier_global_value (get_identifier (SIZE_TYPE)));
- signed_size_type_node = signed_type (size_type_node);
- if (flag_traditional)
- size_type_node = signed_size_type_node;
+ signed_size_type_node = c_common_signed_type (size_type_node);
set_sizetype (size_type_node);
build_common_tree_nodes_2 (flag_short_double);
@@ -2614,14 +3302,18 @@ c_common_nodes_and_builtins ()
record_builtin_type (RID_DOUBLE, NULL, double_type_node);
record_builtin_type (RID_MAX, "long double", long_double_type_node);
- pushdecl (build_decl (TYPE_DECL, get_identifier ("complex int"),
- complex_integer_type_node));
- pushdecl (build_decl (TYPE_DECL, get_identifier ("complex float"),
- complex_float_type_node));
- pushdecl (build_decl (TYPE_DECL, get_identifier ("complex double"),
- complex_double_type_node));
- pushdecl (build_decl (TYPE_DECL, get_identifier ("complex long double"),
- complex_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)
+ (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. */
@@ -2643,12 +3335,12 @@ c_common_nodes_and_builtins ()
if (g77_integer_type_node != NULL_TREE)
{
- pushdecl (build_decl (TYPE_DECL,
- get_identifier ("__g77_integer"),
- g77_integer_type_node));
- pushdecl (build_decl (TYPE_DECL,
- get_identifier ("__g77_uinteger"),
- g77_uinteger_type_node));
+ (*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
@@ -2668,12 +3360,12 @@ c_common_nodes_and_builtins ()
if (g77_longint_type_node != NULL_TREE)
{
- pushdecl (build_decl (TYPE_DECL,
- get_identifier ("__g77_longint"),
- g77_longint_type_node));
- pushdecl (build_decl (TYPE_DECL,
- get_identifier ("__g77_ulongint"),
- g77_ulongint_type_node));
+ (*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));
}
record_builtin_type (RID_VOID, NULL, void_type_node);
@@ -2705,19 +3397,8 @@ c_common_nodes_and_builtins ()
= build_pointer_type (build_qualified_type
(char_type_node, TYPE_QUAL_CONST));
- traditional_ptr_type_node = ((flag_traditional &&
- c_language != clk_cplusplus)
- ? string_type_node : ptr_type_node);
- traditional_cptr_type_node = ((flag_traditional &&
- c_language != clk_cplusplus)
- ? const_string_type_node : const_ptr_type_node);
-
- (*targetm.init_builtins) ();
-
/* This is special for C++ so functions can be overloaded. */
- wchar_type_node = get_identifier (flag_short_wchar
- ? "short unsigned int"
- : WCHAR_TYPE);
+ wchar_type_node = get_identifier (MODIFIED_WCHAR_TYPE);
wchar_type_node = TREE_TYPE (identifier_global_value (wchar_type_node));
wchar_type_size = TYPE_PRECISION (wchar_type_node);
if (c_language == clk_cplusplus)
@@ -2730,8 +3411,8 @@ c_common_nodes_and_builtins ()
}
else
{
- signed_wchar_type_node = signed_type (wchar_type_node);
- unsigned_wchar_type_node = unsigned_type (wchar_type_node);
+ signed_wchar_type_node = c_common_signed_type (wchar_type_node);
+ unsigned_wchar_type_node = c_common_unsigned_type (wchar_type_node);
}
/* This is for wide string constants. */
@@ -2749,16 +3430,19 @@ c_common_nodes_and_builtins ()
default_function_type = build_function_type (integer_type_node, NULL_TREE);
ptrdiff_type_node
= TREE_TYPE (identifier_global_value (get_identifier (PTRDIFF_TYPE)));
- unsigned_ptrdiff_type_node = unsigned_type (ptrdiff_type_node);
+ unsigned_ptrdiff_type_node = c_common_unsigned_type (ptrdiff_type_node);
- 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_va_list"),
+ va_list_type_node));
- pushdecl (build_decl (TYPE_DECL, get_identifier ("__builtin_ptrdiff_t"),
- ptrdiff_type_node));
+ (*lang_hooks.decls.pushdecl)
+ (build_decl (TYPE_DECL, get_identifier ("__builtin_ptrdiff_t"),
+ ptrdiff_type_node));
- pushdecl (build_decl (TYPE_DECL, get_identifier ("__builtin_size_t"),
- sizetype));
+ (*lang_hooks.decls.pushdecl)
+ (build_decl (TYPE_DECL, get_identifier ("__builtin_size_t"),
+ sizetype));
if (TREE_CODE (va_list_type_node) == ARRAY_TYPE)
{
@@ -2771,10 +3455,6 @@ c_common_nodes_and_builtins ()
va_list_ref_type_node = build_reference_type (va_list_type_node);
}
- traditional_len_type_node = ((flag_traditional &&
- c_language != clk_cplusplus)
- ? integer_type_node : sizetype);
-
#define DEF_PRIMITIVE_TYPE(ENUM, VALUE) \
builtin_types[(int) ENUM] = VALUE;
#define DEF_FUNCTION_TYPE_0(ENUM, RETURN) \
@@ -2840,6 +3520,19 @@ c_common_nodes_and_builtins ()
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]);
@@ -2851,10 +3544,15 @@ c_common_nodes_and_builtins ()
#undef DEF_FUNCTION_TYPE_4
#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_POINTER_TYPE
-#define DEF_BUILTIN(ENUM, NAME, CLASS, \
- TYPE, LIBTYPE, BOTH_P, FALLBACK_P, NONANSI_P) \
+ if (!c_attrs_initialized)
+ c_init_attributes ();
+
+#define DEF_BUILTIN(ENUM, NAME, CLASS, TYPE, LIBTYPE, \
+ BOTH_P, FALLBACK_P, NONANSI_P, ATTRS) \
if (NAME) \
{ \
tree decl; \
@@ -2867,7 +3565,8 @@ c_common_nodes_and_builtins ()
CLASS, \
(FALLBACK_P \
? (NAME + strlen ("__builtin_")) \
- : NULL)); \
+ : NULL), \
+ built_in_attributes[(int) ATTRS]); \
else \
decl = builtin_function_2 (NAME, \
NAME + strlen ("__builtin_"), \
@@ -2877,40 +3576,16 @@ c_common_nodes_and_builtins ()
CLASS, \
FALLBACK_P, \
NONANSI_P, \
- /*noreturn_p=*/0); \
+ built_in_attributes[(int) ATTRS]); \
\
built_in_decls[(int) ENUM] = decl; \
}
#include "builtins.def"
#undef DEF_BUILTIN
- /* Declare _exit and _Exit just to mark them as non-returning. */
- builtin_function_2 (NULL, "_exit", NULL_TREE,
- builtin_types[BT_FN_VOID_INT],
- 0, NOT_BUILT_IN, 0, 1, 1);
- builtin_function_2 (NULL, "_Exit", NULL_TREE,
- builtin_types[BT_FN_VOID_INT],
- 0, NOT_BUILT_IN, 0, !flag_isoc99, 1);
-
- /* Declare these functions non-returning
- to avoid spurious "control drops through" warnings. */
- builtin_function_2 (NULL, "abort",
- NULL_TREE, ((c_language == clk_cplusplus)
- ? builtin_types[BT_FN_VOID]
- : builtin_types[BT_FN_VOID_VAR]),
- 0, NOT_BUILT_IN, 0, 0, 1);
-
- builtin_function_2 (NULL, "exit",
- NULL_TREE, ((c_language == clk_cplusplus)
- ? builtin_types[BT_FN_VOID_INT]
- : builtin_types[BT_FN_VOID_VAR]),
- 0, NOT_BUILT_IN, 0, 0, 1);
+ (*targetm.init_builtins) ();
main_identifier_node = get_identifier ("main");
-
- /* ??? Perhaps there's a better place to do this. But it is related
- to __builtin_va_arg, so it isn't that off-the-wall. */
- lang_type_promotes_to = simple_type_promotes_to;
}
tree
@@ -2977,15 +3652,15 @@ builtin_function_disabled_p (name)
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; if
- NORETURN_P is nonzero, the function is marked as non-returning.
+ 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. */
static tree
builtin_function_2 (builtin_name, name, builtin_type, type, function_code,
- class, library_name_p, nonansi_p, noreturn_p)
+ class, library_name_p, nonansi_p, attrs)
const char *builtin_name;
const char *name;
tree builtin_type;
@@ -2994,31 +3669,23 @@ builtin_function_2 (builtin_name, name, builtin_type, type, function_code,
enum built_in_class class;
int library_name_p;
int nonansi_p;
- int noreturn_p;
+ tree attrs;
{
tree bdecl = NULL_TREE;
tree decl = NULL_TREE;
if (builtin_name != 0)
{
bdecl = builtin_function (builtin_name, builtin_type, function_code,
- class, library_name_p ? name : NULL);
- if (noreturn_p)
- {
- TREE_THIS_VOLATILE (bdecl) = 1;
- TREE_SIDE_EFFECTS (bdecl) = 1;
- }
+ class, library_name_p ? name : NULL,
+ attrs);
}
if (name != 0 && !flag_no_builtin && !builtin_function_disabled_p (name)
&& !(nonansi_p && flag_no_nonansi_builtin))
{
- decl = builtin_function (name, type, function_code, class, NULL);
+ decl = builtin_function (name, type, function_code, class, NULL,
+ attrs);
if (nonansi_p)
DECL_BUILT_IN_NONANSI (decl) = 1;
- if (noreturn_p)
- {
- TREE_THIS_VOLATILE (decl) = 1;
- TREE_SIDE_EFFECTS (decl) = 1;
- }
}
return (bdecl != 0 ? bdecl : decl);
}
@@ -3054,34 +3721,6 @@ c_promoting_integer_type_p (t)
}
}
-/* Given a type, apply default promotions wrt unnamed function arguments
- and return the new type. Return NULL_TREE if no change. */
-/* ??? There is a function of the same name in the C++ front end that
- does something similar, but is more thorough and does not return NULL
- if no change. We could perhaps share code, but it would make the
- self_promoting_type property harder to identify. */
-
-tree
-simple_type_promotes_to (type)
- tree type;
-{
- if (TYPE_MAIN_VARIANT (type) == float_type_node)
- return double_type_node;
-
- if (c_promoting_integer_type_p (type))
- {
- /* Traditionally, unsignedness is preserved in default promotions.
- Also preserve unsignedness if not really getting any wider. */
- if (TREE_UNSIGNED (type)
- && (flag_traditional
- || TYPE_PRECISION (type) == TYPE_PRECISION (integer_type_node)))
- return unsigned_type_node;
- return integer_type_node;
- }
-
- return NULL_TREE;
-}
-
/* Return 1 if PARMS specifies a fixed number of parameters
and none of their types is affected by default promotions. */
@@ -3122,6 +3761,81 @@ strip_array_types (type)
return type;
}
+static tree expand_unordered_cmp PARAMS ((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 (function, params, unordered_code, ordered_code)
+ tree function, params;
+ enum tree_code unordered_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. */
@@ -3134,8 +3848,6 @@ tree
expand_tree_builtin (function, params, coerced_params)
tree function, params, coerced_params;
{
- enum tree_code code;
-
if (DECL_BUILT_IN_CLASS (function) != BUILT_IN_NORMAL)
return NULL_TREE;
@@ -3174,72 +3886,22 @@ expand_tree_builtin (function, params, coerced_params)
return build_unary_op (IMAGPART_EXPR, TREE_VALUE (coerced_params), 0);
case BUILT_IN_ISGREATER:
- if (TARGET_FLOAT_FORMAT == IEEE_FLOAT_FORMAT)
- code = UNLE_EXPR;
- else
- code = LE_EXPR;
- goto unordered_cmp;
+ return expand_unordered_cmp (function, params, UNLE_EXPR, LE_EXPR);
case BUILT_IN_ISGREATEREQUAL:
- if (TARGET_FLOAT_FORMAT == IEEE_FLOAT_FORMAT)
- code = UNLT_EXPR;
- else
- code = LT_EXPR;
- goto unordered_cmp;
+ return expand_unordered_cmp (function, params, UNLT_EXPR, LT_EXPR);
case BUILT_IN_ISLESS:
- if (TARGET_FLOAT_FORMAT == IEEE_FLOAT_FORMAT)
- code = UNGE_EXPR;
- else
- code = GE_EXPR;
- goto unordered_cmp;
+ return expand_unordered_cmp (function, params, UNGE_EXPR, GE_EXPR);
case BUILT_IN_ISLESSEQUAL:
- if (TARGET_FLOAT_FORMAT == IEEE_FLOAT_FORMAT)
- code = UNGT_EXPR;
- else
- code = GT_EXPR;
- goto unordered_cmp;
+ return expand_unordered_cmp (function, params, UNGT_EXPR, GT_EXPR);
case BUILT_IN_ISLESSGREATER:
- if (TARGET_FLOAT_FORMAT == IEEE_FLOAT_FORMAT)
- code = UNEQ_EXPR;
- else
- code = EQ_EXPR;
- goto unordered_cmp;
+ return expand_unordered_cmp (function, params, UNEQ_EXPR, EQ_EXPR);
case BUILT_IN_ISUNORDERED:
- if (TARGET_FLOAT_FORMAT != IEEE_FLOAT_FORMAT)
- return integer_zero_node;
- code = UNORDERED_EXPR;
- goto unordered_cmp;
-
- unordered_cmp:
- {
- tree arg0, arg1;
-
- 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));
- arg0 = build_binary_op (code, arg0, arg1, 0);
- if (code != UNORDERED_EXPR)
- arg0 = build_unary_op (TRUTH_NOT_EXPR, arg0, 0);
- return arg0;
- }
- break;
+ return expand_unordered_cmp (function, params, UNORDERED_EXPR, NOP_EXPR);
default:
break;
@@ -3248,7 +3910,7 @@ expand_tree_builtin (function, params, coerced_params)
return NULL_TREE;
}
-/* Returns non-zero if CODE is the code for a statement. */
+/* Returns nonzero if CODE is the code for a statement. */
int
statement_code_p (code)
@@ -3566,41 +4228,6 @@ finish_label_address_expr (label)
return result;
}
-/* Mark P (a stmt_tree) for GC. The use of a `void *' for the
- parameter allows this function to be used as a GC-marking
- function. */
-
-void
-mark_stmt_tree (p)
- void *p;
-{
- stmt_tree st = (stmt_tree) p;
-
- ggc_mark_tree (st->x_last_stmt);
- ggc_mark_tree (st->x_last_expr_type);
-}
-
-/* Mark LD for GC. */
-
-void
-c_mark_lang_decl (c)
- struct c_lang_decl *c ATTRIBUTE_UNUSED;
-{
-}
-
-/* Mark F for GC. */
-
-void
-mark_c_language_function (f)
- struct language_function *f;
-{
- if (!f)
- return;
-
- mark_stmt_tree (&f->x_stmt_tree);
- ggc_mark_tree (f->x_scope_stmt_stack);
-}
-
/* Hook used by expand_expr to expand language-specific tree codes. */
rtx
@@ -3608,7 +4235,7 @@ c_expand_expr (exp, target, tmode, modifier)
tree exp;
rtx target;
enum machine_mode tmode;
- enum expand_modifier modifier;
+ int modifier; /* Actually enum_modifier. */
{
switch (TREE_CODE (exp))
{
@@ -3749,7 +4376,7 @@ c_safe_from_p (target, exp)
/* Hook used by unsafe_for_reeval to handle language-specific tree codes. */
int
-c_unsafe_for_reeval (exp)
+c_common_unsafe_for_reeval (exp)
tree exp;
{
/* Statement expressions may not be reevaluated, likewise compound
@@ -3774,56 +4401,6 @@ c_staticp (exp)
return 0;
}
-/* Tree code classes. */
-
-#define DEFTREECODE(SYM, NAME, TYPE, LENGTH) TYPE,
-
-static const char c_tree_code_type[] = {
- 'x',
-#include "c-common.def"
-};
-#undef DEFTREECODE
-
-/* Table indexed by tree code giving number of expression
- operands beyond the fixed part of the node structure.
- Not used for types or decls. */
-
-#define DEFTREECODE(SYM, NAME, TYPE, LENGTH) LENGTH,
-
-static const int c_tree_code_length[] = {
- 0,
-#include "c-common.def"
-};
-#undef DEFTREECODE
-
-/* Names of tree components.
- Used for printing out the tree and error messages. */
-#define DEFTREECODE(SYM, NAME, TYPE, LEN) NAME,
-
-static const char *const c_tree_code_name[] = {
- "@@dummy",
-#include "c-common.def"
-};
-#undef DEFTREECODE
-
-/* Adds the tree codes specific to the C front end to the list of all
- tree codes. */
-
-void
-add_c_tree_codes ()
-{
- memcpy (tree_code_type + (int) LAST_AND_UNUSED_TREE_CODE,
- c_tree_code_type,
- (int) LAST_C_TREE_CODE - (int) LAST_AND_UNUSED_TREE_CODE);
- memcpy (tree_code_length + (int) LAST_AND_UNUSED_TREE_CODE,
- c_tree_code_length,
- (LAST_C_TREE_CODE - (int) LAST_AND_UNUSED_TREE_CODE) * sizeof (int));
- memcpy (tree_code_name + (int) LAST_AND_UNUSED_TREE_CODE,
- c_tree_code_name,
- (LAST_C_TREE_CODE - (int) LAST_AND_UNUSED_TREE_CODE) * sizeof (char *));
- lang_unsafe_for_reeval = c_unsafe_for_reeval;
-}
-
#define CALLED_AS_BUILT_IN(NODE) \
(!strncmp (IDENTIFIER_POINTER (DECL_NAME (NODE)), "__builtin_", 10))
@@ -4012,7 +4589,7 @@ c_expand_builtin_printf (arglist, target, tmode, modifier, ignore, unlocked)
memcpy (newstr, TREE_STRING_POINTER (stripped_string), newlen - 1);
newstr[newlen - 1] = 0;
- arglist = combine_strings (build_string (newlen, newstr));
+ arglist = fix_string_type (build_string (newlen, newstr));
arglist = build_tree_list (NULL_TREE, arglist);
fn = fn_puts;
}
@@ -4151,112 +4728,449 @@ boolean_increment (code, arg)
return val;
}
-/* Handle C and C++ default attributes. */
+/* Define NAME with value TYPE precision. */
+static void
+builtin_define_type_precision (name, type)
+ const char *name;
+ tree type;
+{
+ builtin_define_with_int_value (name, TYPE_PRECISION (type));
+}
-enum built_in_attribute
+/* Define the float.h constants for TYPE using NAME_PREFIX and FP_SUFFIX. */
+static void
+builtin_define_float_constants (name_prefix, fp_suffix, type)
+ const char *name_prefix;
+ const char *fp_suffix;
+ tree type;
{
-#define DEF_ATTR_NULL_TREE(ENUM) ENUM,
-#define DEF_ATTR_INT(ENUM, VALUE) ENUM,
-#define DEF_ATTR_IDENT(ENUM, STRING) ENUM,
-#define DEF_ATTR_TREE_LIST(ENUM, PURPOSE, VALUE, CHAIN) ENUM,
-#define DEF_FN_ATTR(NAME, ATTRS, PREDICATE) /* No entry needed in enum. */
-#include "builtin-attrs.def"
-#undef DEF_ATTR_NULL_TREE
-#undef DEF_ATTR_INT
-#undef DEF_ATTR_IDENT
-#undef DEF_ATTR_TREE_LIST
-#undef DEF_FN_ATTR
- ATTR_LAST
-};
+ /* Used to convert radix-based values to base 10 values in several cases.
+
+ In the max_exp -> max_10_exp conversion for 128-bit IEEE, we need at
+ least 6 significant digits for correct results. Using the fraction
+ formed by (log(2)*1e6)/(log(10)*1e6) overflows a 32-bit integer as an
+ intermediate; perhaps someone can find a better approximation, in the
+ mean time, I suspect using doubles won't harm the bootstrap here. */
+
+ const double log10_2 = .30102999566398119521;
+ double log10_b;
+ const struct real_format *fmt;
+
+ char name[64], buf[128];
+ int dig, min_10_exp, max_10_exp;
+ int decimal_dig;
+
+ fmt = real_format_for_mode[TYPE_MODE (type) - QFmode];
+
+ /* The radix of the exponent representation. */
+ if (type == float_type_node)
+ builtin_define_with_int_value ("__FLT_RADIX__", fmt->b);
+ log10_b = log10_2 * fmt->log2_b;
+
+ /* The number of radix digits, p, in the floating-point significand. */
+ sprintf (name, "__%s_MANT_DIG__", name_prefix);
+ builtin_define_with_int_value (name, fmt->p);
+
+ /* The number of decimal digits, q, such that any floating-point number
+ with q decimal digits can be rounded into a floating-point number with
+ p radix b digits and back again without change to the q decimal digits,
+
+ p log10 b if b is a power of 10
+ floor((p - 1) log10 b) otherwise
+ */
+ dig = (fmt->p - 1) * log10_b;
+ sprintf (name, "__%s_DIG__", name_prefix);
+ builtin_define_with_int_value (name, dig);
+
+ /* The minimum negative int x such that b**(x-1) is a normalized float. */
+ sprintf (name, "__%s_MIN_EXP__", name_prefix);
+ sprintf (buf, "(%d)", fmt->emin);
+ builtin_define_with_value (name, buf, 0);
+
+ /* The minimum negative int x such that 10**x is a normalized float,
+
+ ceil (log10 (b ** (emin - 1)))
+ = ceil (log10 (b) * (emin - 1))
+
+ Recall that emin is negative, so the integer truncation calculates
+ the ceiling, not the floor, in this case. */
+ min_10_exp = (fmt->emin - 1) * log10_b;
+ sprintf (name, "__%s_MIN_10_EXP__", name_prefix);
+ sprintf (buf, "(%d)", min_10_exp);
+ builtin_define_with_value (name, buf, 0);
+
+ /* The maximum int x such that b**(x-1) is a representable float. */
+ sprintf (name, "__%s_MAX_EXP__", name_prefix);
+ builtin_define_with_int_value (name, fmt->emax);
+
+ /* The maximum int x such that 10**x is in the range of representable
+ finite floating-point numbers,
+
+ floor (log10((1 - b**-p) * b**emax))
+ = floor (log10(1 - b**-p) + log10(b**emax))
+ = floor (log10(1 - b**-p) + log10(b)*emax)
+
+ The safest thing to do here is to just compute this number. But since
+ we don't link cc1 with libm, we cannot. We could implement log10 here
+ a series expansion, but that seems too much effort because:
+
+ Note that the first term, for all extant p, is a number exceedingly close
+ to zero, but slightly negative. Note that the second term is an integer
+ scaling an irrational number, and that because of the floor we are only
+ interested in its integral portion.
+
+ In order for the first term to have any effect on the integral portion
+ of the second term, the second term has to be exceedingly close to an
+ integer itself (e.g. 123.000000000001 or something). Getting a result
+ that close to an integer requires that the irrational multiplicand have
+ a long series of zeros in its expansion, which doesn't occur in the
+ first 20 digits or so of log10(b).
+
+ Hand-waving aside, crunching all of the sets of constants above by hand
+ does not yield a case for which the first term is significant, which
+ in the end is all that matters. */
+ max_10_exp = fmt->emax * log10_b;
+ sprintf (name, "__%s_MAX_10_EXP__", name_prefix);
+ builtin_define_with_int_value (name, max_10_exp);
+
+ /* The number of decimal digits, n, such that any floating-point number
+ can be rounded to n decimal digits and back again without change to
+ the value.
+
+ p * log10(b) if b is a power of 10
+ ceil(1 + p * log10(b)) otherwise
+
+ The only macro we care about is this number for the widest supported
+ floating type, but we want this value for rendering constants below. */
+ {
+ double d_decimal_dig = 1 + fmt->p * log10_b;
+ decimal_dig = d_decimal_dig;
+ if (decimal_dig < d_decimal_dig)
+ decimal_dig++;
+ }
+ if (type == long_double_type_node)
+ builtin_define_with_int_value ("__DECIMAL_DIG__", decimal_dig);
+
+ /* Since, for the supported formats, B is always a power of 2, we
+ construct the following numbers directly as a hexadecimal
+ constants. */
+
+ /* The maximum representable finite floating-point number,
+ (1 - b**-p) * b**emax */
+ {
+ int i, n;
+ char *p;
+
+ strcpy (buf, "0x0.");
+ n = fmt->p * fmt->log2_b;
+ for (i = 0, p = buf + 4; i + 3 < n; i += 4)
+ *p++ = 'f';
+ if (i < n)
+ *p++ = "08ce"[n - i];
+ sprintf (p, "p%d", fmt->emax * fmt->log2_b);
+ }
+ sprintf (name, "__%s_MAX__", name_prefix);
+ builtin_define_with_hex_fp_value (name, type, decimal_dig, buf, fp_suffix);
+
+ /* The minimum normalized positive floating-point number,
+ b**(emin-1). */
+ sprintf (name, "__%s_MIN__", name_prefix);
+ sprintf (buf, "0x1p%d", (fmt->emin - 1) * fmt->log2_b);
+ builtin_define_with_hex_fp_value (name, type, decimal_dig, buf, fp_suffix);
+
+ /* The difference between 1 and the least value greater than 1 that is
+ representable in the given floating point type, b**(1-p). */
+ sprintf (name, "__%s_EPSILON__", name_prefix);
+ sprintf (buf, "0x1p%d", (1 - fmt->p) * fmt->log2_b);
+ builtin_define_with_hex_fp_value (name, type, decimal_dig, buf, fp_suffix);
+
+ /* For C++ std::numeric_limits<T>::denorm_min. The minimum denormalized
+ positive floating-point number, b**(emin-p). Zero for formats that
+ don't support denormals. */
+ sprintf (name, "__%s_DENORM_MIN__", name_prefix);
+ if (fmt->has_denorm)
+ {
+ sprintf (buf, "0x1p%d", (fmt->emin - fmt->p) * fmt->log2_b);
+ builtin_define_with_hex_fp_value (name, type, decimal_dig,
+ buf, fp_suffix);
+ }
+ else
+ {
+ sprintf (buf, "0.0%s", fp_suffix);
+ builtin_define_with_value (name, buf, 0);
+ }
+}
-static tree built_in_attributes[(int) ATTR_LAST];
+/* Hook that registers front end and target-specific built-ins. */
+void
+cb_register_builtins (pfile)
+ cpp_reader *pfile;
+{
+ /* -undef turns off target-specific built-ins. */
+ if (flag_undef)
+ return;
-static bool c_attrs_initialized = false;
+ if (c_language == clk_cplusplus)
+ {
+ if (SUPPORTS_ONE_ONLY)
+ cpp_define (pfile, "__GXX_WEAK__=1");
+ else
+ cpp_define (pfile, "__GXX_WEAK__=0");
+ if (warn_deprecated)
+ cpp_define (pfile, "__DEPRECATED");
+ }
+ if (flag_exceptions)
+ cpp_define (pfile, "__EXCEPTIONS");
+
+ /* represents the C++ ABI version, always defined so it can be used while
+ preprocessing C and assembler. */
+ cpp_define (pfile, "__GXX_ABI_VERSION=102");
+
+ /* libgcc needs to know this. */
+ if (USING_SJLJ_EXCEPTIONS)
+ cpp_define (pfile, "__USING_SJLJ_EXCEPTIONS__");
+
+ /* stddef.h needs to know these. */
+ builtin_define_with_value ("__SIZE_TYPE__", SIZE_TYPE, 0);
+ 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);
+
+ /* limits.h needs to know these. */
+ builtin_define_type_max ("__SCHAR_MAX__", signed_char_type_node, 0);
+ builtin_define_type_max ("__SHRT_MAX__", short_integer_type_node, 0);
+ builtin_define_type_max ("__INT_MAX__", integer_type_node, 0);
+ builtin_define_type_max ("__LONG_MAX__", long_integer_type_node, 1);
+ builtin_define_type_max ("__LONG_LONG_MAX__", long_long_integer_type_node, 2);
+ builtin_define_type_max ("__WCHAR_MAX__", wchar_type_node, 0);
+
+ builtin_define_type_precision ("__CHAR_BIT__", char_type_node);
+
+ /* float.h needs to know these. */
+
+ builtin_define_with_int_value ("__FLT_EVAL_METHOD__",
+ TARGET_FLT_EVAL_METHOD);
+
+ builtin_define_float_constants ("FLT", "F", float_type_node);
+ builtin_define_float_constants ("DBL", "", double_type_node);
+ builtin_define_float_constants ("LDBL", "L", long_double_type_node);
+
+ /* For use in assembly language. */
+ builtin_define_with_value ("__REGISTER_PREFIX__", REGISTER_PREFIX, 0);
+ builtin_define_with_value ("__USER_LABEL_PREFIX__", user_label_prefix, 0);
+
+ /* Misc. */
+ builtin_define_with_value ("__VERSION__", version_string, 1);
+
+ /* Other target-independent built-ins determined by command-line
+ options. */
+ if (optimize_size)
+ cpp_define (pfile, "__OPTIMIZE_SIZE__");
+ if (optimize)
+ cpp_define (pfile, "__OPTIMIZE__");
+
+ if (flag_hosted)
+ cpp_define (pfile, "__STDC_HOSTED__=1");
+ else
+ cpp_define (pfile, "__STDC_HOSTED__=0");
+
+ if (fast_math_flags_set_p ())
+ cpp_define (pfile, "__FAST_MATH__");
+ if (flag_really_no_inline)
+ cpp_define (pfile, "__NO_INLINE__");
+ if (flag_signaling_nans)
+ cpp_define (pfile, "__SUPPORT_SNAN__");
+ if (flag_finite_math_only)
+ cpp_define (pfile, "__FINITE_MATH_ONLY__=1");
+ else
+ cpp_define (pfile, "__FINITE_MATH_ONLY__=0");
-static void c_init_attributes PARAMS ((void));
+ if (flag_iso)
+ cpp_define (pfile, "__STRICT_ANSI__");
-/* Common initialization before parsing options. */
-void
-c_common_init_options (lang)
- enum c_language_kind lang;
-{
- c_language = lang;
- parse_in = cpp_create_reader (lang == clk_c ? CLK_GNUC89:
- lang == clk_cplusplus ? CLK_GNUCXX: CLK_OBJC);
+ if (!flag_signed_char)
+ cpp_define (pfile, "__CHAR_UNSIGNED__");
- /* Mark as "unspecified" (see c_common_post_options). */
- flag_bounds_check = -1;
+ if (c_language == clk_cplusplus && TREE_UNSIGNED (wchar_type_node))
+ cpp_define (pfile, "__WCHAR_UNSIGNED__");
+
+ /* Make the choice of ObjC runtime visible to source code. */
+ if (flag_objc && flag_next_runtime)
+ cpp_define (pfile, "__NEXT_RUNTIME__");
+
+ /* A straightforward target hook doesn't work, because of problems
+ linking that hook's body when part of non-C front ends. */
+# define preprocessing_asm_p() (cpp_get_options (pfile)->lang == CLK_ASM)
+# define preprocessing_trad_p() (cpp_get_options (pfile)->traditional)
+# define builtin_define(TXT) cpp_define (pfile, TXT)
+# define builtin_assert(TXT) cpp_assert (pfile, TXT)
+ TARGET_CPU_CPP_BUILTINS ();
+ TARGET_OS_CPP_BUILTINS ();
}
-/* Post-switch processing. */
+/* Pass an object-like macro. If it doesn't lie in the user's
+ namespace, defines it unconditionally. Otherwise define a version
+ with two leading underscores, and another version with two leading
+ and trailing underscores, and define the original only if an ISO
+ standard was not nominated.
+
+ e.g. passing "unix" defines "__unix", "__unix__" and possibly
+ "unix". Passing "_mips" defines "__mips", "__mips__" and possibly
+ "_mips". */
void
-c_common_post_options ()
+builtin_define_std (macro)
+ const char *macro;
{
- cpp_post_options (parse_in);
-
- flag_inline_trees = 1;
+ size_t len = strlen (macro);
+ char *buff = alloca (len + 5);
+ char *p = buff + 2;
+ char *q = p + len;
+
+ /* prepend __ (or maybe just _) if in user's namespace. */
+ memcpy (p, macro, len + 1);
+ if (!( *p == '_' && (p[1] == '_' || ISUPPER (p[1]))))
+ {
+ if (*p != '_')
+ *--p = '_';
+ if (p[1] != '_')
+ *--p = '_';
+ }
+ cpp_define (parse_in, p);
- /* Use tree inlining if possible. Function instrumentation is only
- done in the RTL level, so we disable tree inlining. */
- if (! flag_instrument_function_entry_exit)
+ /* If it was in user's namespace... */
+ if (p != buff + 2)
{
- if (!flag_no_inline)
- flag_no_inline = 1;
- if (flag_inline_functions)
- {
- flag_inline_trees = 2;
- flag_inline_functions = 0;
- }
+ /* Define the macro with leading and following __. */
+ if (q[-1] != '_')
+ *q++ = '_';
+ if (q[-2] != '_')
+ *q++ = '_';
+ *q = '\0';
+ cpp_define (parse_in, p);
+
+ /* Finally, define the original macro if permitted. */
+ if (!flag_iso)
+ cpp_define (parse_in, macro);
}
+}
+
+/* Pass an object-like macro and a value to define it to. The third
+ parameter says whether or not to turn the value into a string
+ constant. */
+static void
+builtin_define_with_value (macro, expansion, is_str)
+ const char *macro;
+ const char *expansion;
+ int is_str;
+{
+ char *buf;
+ size_t mlen = strlen (macro);
+ size_t elen = strlen (expansion);
+ size_t extra = 2; /* space for an = and a NUL */
- /* If still "unspecified", make it match -fbounded-pointers. */
- if (flag_bounds_check == -1)
- flag_bounds_check = flag_bounded_pointers;
-
- /* Special format checking options don't work without -Wformat; warn if
- they are used. */
- if (warn_format_y2k && !warn_format)
- warning ("-Wformat-y2k ignored without -Wformat");
- if (warn_format_extra_args && !warn_format)
- warning ("-Wformat-extra-args ignored without -Wformat");
- if (warn_format_nonliteral && !warn_format)
- warning ("-Wformat-nonliteral ignored without -Wformat");
- if (warn_format_security && !warn_format)
- warning ("-Wformat-security ignored without -Wformat");
- if (warn_missing_format_attribute && !warn_format)
- warning ("-Wmissing-format-attribute ignored without -Wformat");
-
- /* If an error has occurred in cpplib, note it so we fail
- immediately. */
- errorcount += cpp_errors (parse_in);
+ if (is_str)
+ extra += 2; /* space for two quote marks */
+
+ buf = alloca (mlen + elen + extra);
+ if (is_str)
+ sprintf (buf, "%s=\"%s\"", macro, expansion);
+ else
+ sprintf (buf, "%s=%s", macro, expansion);
+
+ cpp_define (parse_in, buf);
}
-/* Front end initialization common to C, ObjC and C++. */
-const char *
-c_common_init (filename)
- const char *filename;
+/* Pass an object-like macro and an integer value to define it to. */
+static void
+builtin_define_with_int_value (macro, value)
+ const char *macro;
+ HOST_WIDE_INT value;
{
- /* Do this before initializing pragmas, as then cpplib's hash table
- has been set up. */
- filename = init_c_lex (filename);
+ char *buf;
+ size_t mlen = strlen (macro);
+ size_t vlen = 18;
+ size_t extra = 2; /* space for = and NUL. */
- init_pragma ();
+ buf = alloca (mlen + vlen + extra);
+ memcpy (buf, macro, mlen);
+ buf[mlen] = '=';
+ sprintf (buf + mlen + 1, HOST_WIDE_INT_PRINT_DEC, value);
- if (!c_attrs_initialized)
- c_init_attributes ();
+ cpp_define (parse_in, buf);
+}
- return filename;
+/* Pass an object-like macro a hexadecimal floating-point value. */
+static void
+builtin_define_with_hex_fp_value (macro, type, digits, hex_str, fp_suffix)
+ const char *macro;
+ tree type ATTRIBUTE_UNUSED;
+ int digits;
+ const char *hex_str;
+ const char *fp_suffix;
+{
+ REAL_VALUE_TYPE real;
+ char dec_str[64], buf[256];
+
+ /* Hex values are really cool and convenient, except that they're
+ not supported in strict ISO C90 mode. First, the "p-" sequence
+ is not valid as part of a preprocessor number. Second, we get a
+ pedwarn from the preprocessor, which has no context, so we can't
+ suppress the warning with __extension__.
+
+ So instead what we do is construct the number in hex (because
+ it's easy to get the exact correct value), parse it as a real,
+ then print it back out as decimal. */
+
+ real_from_string (&real, hex_str);
+ real_to_decimal (dec_str, &real, sizeof (dec_str), digits, 0);
+
+ sprintf (buf, "%s=%s%s", macro, dec_str, fp_suffix);
+ cpp_define (parse_in, buf);
}
-/* Common finish hook for the C, ObjC and C++ front ends. */
-void
-c_common_finish ()
+/* Define MAX for TYPE based on the precision of the type. IS_LONG is
+ 1 for type "long" and 2 for "long long". We have to handle
+ unsigned types, since wchar_t might be unsigned. */
+
+static void
+builtin_define_type_max (macro, type, is_long)
+ const char *macro;
+ tree type;
+ int is_long;
{
- cpp_finish (parse_in);
+ static const char *const values[]
+ = { "127", "255",
+ "32767", "65535",
+ "2147483647", "4294967295",
+ "9223372036854775807", "18446744073709551615",
+ "170141183460469231731687303715884105727",
+ "340282366920938463463374607431768211455" };
+ static const char *const suffixes[] = { "", "U", "L", "UL", "LL", "ULL" };
+
+ const char *value, *suffix;
+ char *buf;
+ size_t idx;
+
+ /* Pre-rendering the values mean we don't have to futz with printing a
+ multi-word decimal value. There are also a very limited number of
+ precisions that we support, so it's really a waste of time. */
+ switch (TYPE_PRECISION (type))
+ {
+ case 8: idx = 0; break;
+ case 16: idx = 2; break;
+ case 32: idx = 4; break;
+ case 64: idx = 6; break;
+ case 128: idx = 8; break;
+ default: abort ();
+ }
+
+ value = values[idx + TREE_UNSIGNED (type)];
+ suffix = suffixes[is_long * 2 + TREE_UNSIGNED (type)];
- /* For performance, avoid tearing down cpplib's internal structures.
- Call cpp_errors () instead of cpp_destroy (). */
- errorcount += cpp_errors (parse_in);
+ buf = alloca (strlen (macro) + 1 + strlen (value) + strlen (suffix) + 1);
+ sprintf (buf, "%s=%s%s", macro, value, suffix);
+
+ cpp_define (parse_in, buf);
}
static void
@@ -4281,7 +5195,6 @@ c_init_attributes ()
#undef DEF_ATTR_IDENT
#undef DEF_ATTR_TREE_LIST
#undef DEF_FN_ATTR
- ggc_add_tree_root (built_in_attributes, (int) ATTR_LAST);
c_attrs_initialized = true;
}
@@ -4325,3 +5238,1447 @@ shadow_warning (msgid, name, decl)
"shadowed declaration is here");
}
+/* Attribute handlers common to C front ends. */
+
+/* Handle a "packed" attribute; arguments as in
+ struct attribute_spec.handler. */
+
+static tree
+handle_packed_attribute (node, name, args, flags, no_add_attrs)
+ tree *node;
+ tree name;
+ tree args ATTRIBUTE_UNUSED;
+ int flags;
+ bool *no_add_attrs;
+{
+ tree *type = NULL;
+ if (DECL_P (*node))
+ {
+ if (TREE_CODE (*node) == TYPE_DECL)
+ type = &TREE_TYPE (*node);
+ }
+ else
+ type = node;
+
+ if (type)
+ {
+ if (!(flags & (int) ATTR_FLAG_TYPE_IN_PLACE))
+ *type = build_type_copy (*type);
+ TYPE_PACKED (*type) = 1;
+ }
+ else if (TREE_CODE (*node) == FIELD_DECL)
+ 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. */
+ else
+ {
+ warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
+ *no_add_attrs = true;
+ }
+
+ return NULL_TREE;
+}
+
+/* Handle a "nocommon" attribute; arguments as in
+ struct attribute_spec.handler. */
+
+static tree
+handle_nocommon_attribute (node, name, args, flags, no_add_attrs)
+ tree *node;
+ tree name;
+ tree args ATTRIBUTE_UNUSED;
+ int flags ATTRIBUTE_UNUSED;
+ bool *no_add_attrs;
+{
+ if (TREE_CODE (*node) == VAR_DECL)
+ DECL_COMMON (*node) = 0;
+ else
+ {
+ warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
+ *no_add_attrs = true;
+ }
+
+ return NULL_TREE;
+}
+
+/* Handle a "common" attribute; arguments as in
+ struct attribute_spec.handler. */
+
+static tree
+handle_common_attribute (node, name, args, flags, no_add_attrs)
+ tree *node;
+ tree name;
+ tree args ATTRIBUTE_UNUSED;
+ int flags ATTRIBUTE_UNUSED;
+ bool *no_add_attrs;
+{
+ if (TREE_CODE (*node) == VAR_DECL)
+ DECL_COMMON (*node) = 1;
+ else
+ {
+ warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
+ *no_add_attrs = true;
+ }
+
+ return NULL_TREE;
+}
+
+/* Handle a "noreturn" attribute; arguments as in
+ struct attribute_spec.handler. */
+
+static tree
+handle_noreturn_attribute (node, name, args, flags, no_add_attrs)
+ tree *node;
+ tree name;
+ tree args ATTRIBUTE_UNUSED;
+ int flags ATTRIBUTE_UNUSED;
+ bool *no_add_attrs;
+{
+ tree type = TREE_TYPE (*node);
+
+ /* See FIXME comment in c_common_attribute_table. */
+ if (TREE_CODE (*node) == FUNCTION_DECL)
+ TREE_THIS_VOLATILE (*node) = 1;
+ else if (TREE_CODE (type) == POINTER_TYPE
+ && TREE_CODE (TREE_TYPE (type)) == FUNCTION_TYPE)
+ TREE_TYPE (*node)
+ = build_pointer_type
+ (build_type_variant (TREE_TYPE (type),
+ TREE_READONLY (TREE_TYPE (type)), 1));
+ else
+ {
+ warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
+ *no_add_attrs = true;
+ }
+
+ return NULL_TREE;
+}
+
+/* Handle a "noinline" attribute; arguments as in
+ struct attribute_spec.handler. */
+
+static tree
+handle_noinline_attribute (node, name, args, flags, no_add_attrs)
+ tree *node;
+ tree name;
+ tree args ATTRIBUTE_UNUSED;
+ int flags ATTRIBUTE_UNUSED;
+ bool *no_add_attrs;
+{
+ if (TREE_CODE (*node) == FUNCTION_DECL)
+ DECL_UNINLINABLE (*node) = 1;
+ else
+ {
+ warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
+ *no_add_attrs = true;
+ }
+
+ return NULL_TREE;
+}
+
+/* Handle a "always_inline" attribute; arguments as in
+ struct attribute_spec.handler. */
+
+static tree
+handle_always_inline_attribute (node, name, args, flags, no_add_attrs)
+ 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 ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
+ *no_add_attrs = true;
+ }
+
+ return NULL_TREE;
+}
+
+/* Handle a "used" attribute; arguments as in
+ struct attribute_spec.handler. */
+
+static tree
+handle_used_attribute (pnode, name, args, flags, no_add_attrs)
+ tree *pnode;
+ tree name;
+ tree args ATTRIBUTE_UNUSED;
+ int flags ATTRIBUTE_UNUSED;
+ bool *no_add_attrs;
+{
+ tree node = *pnode;
+
+ if (TREE_CODE (node) == FUNCTION_DECL
+ || (TREE_CODE (node) == VAR_DECL && TREE_STATIC (node)))
+ TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (node))
+ = TREE_USED (node) = 1;
+ else
+ {
+ warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
+ *no_add_attrs = true;
+ }
+
+ return NULL_TREE;
+}
+
+/* Handle a "unused" attribute; arguments as in
+ struct attribute_spec.handler. */
+
+static tree
+handle_unused_attribute (node, name, args, flags, no_add_attrs)
+ tree *node;
+ tree name;
+ tree args ATTRIBUTE_UNUSED;
+ int flags;
+ bool *no_add_attrs;
+{
+ if (DECL_P (*node))
+ {
+ tree decl = *node;
+
+ if (TREE_CODE (decl) == PARM_DECL
+ || TREE_CODE (decl) == VAR_DECL
+ || TREE_CODE (decl) == FUNCTION_DECL
+ || TREE_CODE (decl) == LABEL_DECL
+ || TREE_CODE (decl) == TYPE_DECL)
+ TREE_USED (decl) = 1;
+ else
+ {
+ warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
+ *no_add_attrs = true;
+ }
+ }
+ else
+ {
+ if (!(flags & (int) ATTR_FLAG_TYPE_IN_PLACE))
+ *node = build_type_copy (*node);
+ TREE_USED (*node) = 1;
+ }
+
+ return NULL_TREE;
+}
+
+/* Handle a "const" attribute; arguments as in
+ struct attribute_spec.handler. */
+
+static tree
+handle_const_attribute (node, name, args, flags, no_add_attrs)
+ tree *node;
+ tree name;
+ tree args ATTRIBUTE_UNUSED;
+ int flags ATTRIBUTE_UNUSED;
+ bool *no_add_attrs;
+{
+ tree type = TREE_TYPE (*node);
+
+ /* See FIXME comment on noreturn in c_common_attribute_table. */
+ if (TREE_CODE (*node) == FUNCTION_DECL)
+ TREE_READONLY (*node) = 1;
+ else if (TREE_CODE (type) == POINTER_TYPE
+ && TREE_CODE (TREE_TYPE (type)) == FUNCTION_TYPE)
+ TREE_TYPE (*node)
+ = build_pointer_type
+ (build_type_variant (TREE_TYPE (type), 1,
+ TREE_THIS_VOLATILE (TREE_TYPE (type))));
+ else
+ {
+ warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
+ *no_add_attrs = true;
+ }
+
+ return NULL_TREE;
+}
+
+/* Handle a "transparent_union" attribute; arguments as in
+ struct attribute_spec.handler. */
+
+static tree
+handle_transparent_union_attribute (node, name, args, flags, no_add_attrs)
+ tree *node;
+ tree name;
+ tree args ATTRIBUTE_UNUSED;
+ int flags;
+ bool *no_add_attrs;
+{
+ tree decl = NULL_TREE;
+ tree *type = NULL;
+ int is_type = 0;
+
+ if (DECL_P (*node))
+ {
+ decl = *node;
+ type = &TREE_TYPE (decl);
+ is_type = TREE_CODE (*node) == TYPE_DECL;
+ }
+ else if (TYPE_P (*node))
+ type = node, is_type = 1;
+
+ if (is_type
+ && TREE_CODE (*type) == UNION_TYPE
+ && (decl == 0
+ || (TYPE_FIELDS (*type) != 0
+ && TYPE_MODE (*type) == DECL_MODE (TYPE_FIELDS (*type)))))
+ {
+ 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;
+ }
+
+ return NULL_TREE;
+}
+
+/* Handle a "constructor" attribute; arguments as in
+ struct attribute_spec.handler. */
+
+static tree
+handle_constructor_attribute (node, name, args, flags, no_add_attrs)
+ tree *node;
+ tree name;
+ tree args ATTRIBUTE_UNUSED;
+ int flags ATTRIBUTE_UNUSED;
+ bool *no_add_attrs;
+{
+ tree decl = *node;
+ tree type = TREE_TYPE (decl);
+
+ if (TREE_CODE (decl) == FUNCTION_DECL
+ && TREE_CODE (type) == FUNCTION_TYPE
+ && decl_function_context (decl) == 0)
+ {
+ DECL_STATIC_CONSTRUCTOR (decl) = 1;
+ TREE_USED (decl) = 1;
+ }
+ else
+ {
+ warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
+ *no_add_attrs = true;
+ }
+
+ return NULL_TREE;
+}
+
+/* Handle a "destructor" attribute; arguments as in
+ struct attribute_spec.handler. */
+
+static tree
+handle_destructor_attribute (node, name, args, flags, no_add_attrs)
+ tree *node;
+ tree name;
+ tree args ATTRIBUTE_UNUSED;
+ int flags ATTRIBUTE_UNUSED;
+ bool *no_add_attrs;
+{
+ tree decl = *node;
+ tree type = TREE_TYPE (decl);
+
+ if (TREE_CODE (decl) == FUNCTION_DECL
+ && TREE_CODE (type) == FUNCTION_TYPE
+ && decl_function_context (decl) == 0)
+ {
+ DECL_STATIC_DESTRUCTOR (decl) = 1;
+ TREE_USED (decl) = 1;
+ }
+ else
+ {
+ warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
+ *no_add_attrs = true;
+ }
+
+ return NULL_TREE;
+}
+
+/* Handle a "mode" attribute; arguments as in
+ struct attribute_spec.handler. */
+
+static tree
+handle_mode_attribute (node, name, args, flags, no_add_attrs)
+ tree *node;
+ tree name;
+ tree args;
+ int flags ATTRIBUTE_UNUSED;
+ 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));
+ else
+ {
+ int j;
+ const char *p = IDENTIFIER_POINTER (TREE_VALUE (args));
+ int len = strlen (p);
+ enum machine_mode mode = VOIDmode;
+ tree typefm;
+
+ if (len > 4 && p[0] == '_' && p[1] == '_'
+ && p[len - 1] == '_' && p[len - 2] == '_')
+ {
+ char *newp = (char *) alloca (len - 1);
+
+ strcpy (newp, &p[2]);
+ newp[len - 4] = '\0';
+ p = newp;
+ }
+
+ /* Change this type to have a type with the specified mode.
+ First check for the special modes. */
+ if (! strcmp (p, "byte"))
+ mode = byte_mode;
+ else if (!strcmp (p, "word"))
+ mode = word_mode;
+ else if (! strcmp (p, "pointer"))
+ mode = ptr_mode;
+ else
+ for (j = 0; j < NUM_MACHINE_MODES; j++)
+ if (!strcmp (p, GET_MODE_NAME (j)))
+ mode = (enum machine_mode) j;
+
+ if (mode == VOIDmode)
+ error ("unknown machine mode `%s'", p);
+ else if (0 == (typefm = (*lang_hooks.types.type_for_mode)
+ (mode, TREE_UNSIGNED (type))))
+ error ("no data type for mode `%s'", p);
+ else
+ {
+ /* 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;
+ }
+
+ *node = typefm;
+ /* No need to layout the type here. The caller should do this. */
+ }
+ }
+
+ return NULL_TREE;
+}
+
+/* Handle a "section" attribute; arguments as in
+ struct attribute_spec.handler. */
+
+static tree
+handle_section_attribute (node, name, args, flags, no_add_attrs)
+ tree *node;
+ tree name ATTRIBUTE_UNUSED;
+ tree args;
+ int flags ATTRIBUTE_UNUSED;
+ bool *no_add_attrs;
+{
+ tree decl = *node;
+
+ if (targetm.have_named_sections)
+ {
+ if ((TREE_CODE (decl) == FUNCTION_DECL
+ || TREE_CODE (decl) == VAR_DECL)
+ && TREE_CODE (TREE_VALUE (args)) == STRING_CST)
+ {
+ if (TREE_CODE (decl) == VAR_DECL
+ && current_function_decl != NULL_TREE
+ && ! TREE_STATIC (decl))
+ {
+ error_with_decl (decl,
+ "section attribute cannot be specified for local variables");
+ *no_add_attrs = true;
+ }
+
+ /* The decl may have already been given a section attribute
+ from a previous declaration. Ensure they match. */
+ else if (DECL_SECTION_NAME (decl) != NULL_TREE
+ && strcmp (TREE_STRING_POINTER (DECL_SECTION_NAME (decl)),
+ TREE_STRING_POINTER (TREE_VALUE (args))) != 0)
+ {
+ error_with_decl (*node,
+ "section of `%s' conflicts with previous declaration");
+ *no_add_attrs = true;
+ }
+ else
+ DECL_SECTION_NAME (decl) = TREE_VALUE (args);
+ }
+ else
+ {
+ error_with_decl (*node,
+ "section attribute not allowed for `%s'");
+ *no_add_attrs = true;
+ }
+ }
+ else
+ {
+ error_with_decl (*node,
+ "section attributes are not supported for this target");
+ *no_add_attrs = true;
+ }
+
+ return NULL_TREE;
+}
+
+/* Handle a "aligned" attribute; arguments as in
+ struct attribute_spec.handler. */
+
+static tree
+handle_aligned_attribute (node, name, args, flags, no_add_attrs)
+ tree *node;
+ tree name ATTRIBUTE_UNUSED;
+ tree args;
+ int flags;
+ bool *no_add_attrs;
+{
+ tree decl = NULL_TREE;
+ tree *type = NULL;
+ int is_type = 0;
+ tree align_expr = (args ? TREE_VALUE (args)
+ : size_int (BIGGEST_ALIGNMENT / BITS_PER_UNIT));
+ int i;
+
+ if (DECL_P (*node))
+ {
+ decl = *node;
+ type = &TREE_TYPE (decl);
+ is_type = TREE_CODE (*node) == TYPE_DECL;
+ }
+ 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");
+ *no_add_attrs = true;
+ }
+ else if ((i = tree_log2 (align_expr)) == -1)
+ {
+ error ("requested alignment is not a power of 2");
+ *no_add_attrs = true;
+ }
+ else if (i > HOST_BITS_PER_INT - 2)
+ {
+ error ("requested alignment is too large");
+ *no_add_attrs = true;
+ }
+ else if (is_type)
+ {
+ /* If we have a TYPE_DECL, then copy the type, so that we
+ don't accidentally modify a builtin type. See pushdecl. */
+ if (decl && TREE_TYPE (decl) != error_mark_node
+ && DECL_ORIGINAL_TYPE (decl) == NULL_TREE)
+ {
+ tree tt = TREE_TYPE (decl);
+ *type = build_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_ALIGN (*type) = (1 << i) * BITS_PER_UNIT;
+ TYPE_USER_ALIGN (*type) = 1;
+ }
+ else if (TREE_CODE (decl) != VAR_DECL
+ && TREE_CODE (decl) != FIELD_DECL)
+ {
+ error_with_decl (decl,
+ "alignment may not be specified for `%s'");
+ *no_add_attrs = true;
+ }
+ else
+ {
+ DECL_ALIGN (decl) = (1 << i) * BITS_PER_UNIT;
+ DECL_USER_ALIGN (decl) = 1;
+ }
+
+ return NULL_TREE;
+}
+
+/* Handle a "weak" attribute; arguments as in
+ struct attribute_spec.handler. */
+
+static tree
+handle_weak_attribute (node, name, args, flags, no_add_attrs)
+ tree *node;
+ tree name ATTRIBUTE_UNUSED;
+ tree args ATTRIBUTE_UNUSED;
+ int flags ATTRIBUTE_UNUSED;
+ bool *no_add_attrs ATTRIBUTE_UNUSED;
+{
+ declare_weak (*node);
+
+ return NULL_TREE;
+}
+
+/* Handle an "alias" attribute; arguments as in
+ struct attribute_spec.handler. */
+
+static tree
+handle_alias_attribute (node, name, args, flags, no_add_attrs)
+ tree *node;
+ tree name;
+ tree args;
+ int flags ATTRIBUTE_UNUSED;
+ 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_with_decl (decl,
+ "`%s' defined both normally and as an alias");
+ *no_add_attrs = true;
+ }
+ else if (decl_function_context (decl) == 0)
+ {
+ tree id;
+
+ id = TREE_VALUE (args);
+ if (TREE_CODE (id) != STRING_CST)
+ {
+ error ("alias arg not a string");
+ *no_add_attrs = true;
+ return NULL_TREE;
+ }
+ id = get_identifier (TREE_STRING_POINTER (id));
+ /* This counts as a use of the object pointed to. */
+ TREE_USED (id) = 1;
+
+ if (TREE_CODE (decl) == FUNCTION_DECL)
+ DECL_INITIAL (decl) = error_mark_node;
+ else
+ DECL_EXTERNAL (decl) = 0;
+ }
+ else
+ {
+ warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
+ *no_add_attrs = true;
+ }
+
+ return NULL_TREE;
+}
+
+/* Handle an "visibility" attribute; arguments as in
+ struct attribute_spec.handler. */
+
+static tree
+handle_visibility_attribute (node, name, args, flags, no_add_attrs)
+ tree *node;
+ tree name;
+ tree args;
+ int flags ATTRIBUTE_UNUSED;
+ bool *no_add_attrs;
+{
+ tree decl = *node;
+
+ if (decl_function_context (decl) != 0 || ! TREE_PUBLIC (decl))
+ {
+ warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
+ *no_add_attrs = true;
+ }
+ else
+ {
+ tree id;
+
+ id = TREE_VALUE (args);
+ if (TREE_CODE (id) != STRING_CST)
+ {
+ error ("visibility arg not a string");
+ *no_add_attrs = true;
+ return NULL_TREE;
+ }
+ if (strcmp (TREE_STRING_POINTER (id), "hidden")
+ && strcmp (TREE_STRING_POINTER (id), "protected")
+ && strcmp (TREE_STRING_POINTER (id), "internal")
+ && strcmp (TREE_STRING_POINTER (id), "default"))
+ {
+ error ("visibility arg must be one of \"default\", \"hidden\", \"protected\" or \"internal\"");
+ *no_add_attrs = true;
+ return NULL_TREE;
+ }
+ }
+
+ return NULL_TREE;
+}
+
+/* Handle an "tls_model" attribute; arguments as in
+ struct attribute_spec.handler. */
+
+static tree
+handle_tls_model_attribute (node, name, args, flags, no_add_attrs)
+ tree *node;
+ tree name;
+ tree args;
+ int flags ATTRIBUTE_UNUSED;
+ bool *no_add_attrs;
+{
+ tree decl = *node;
+
+ if (! DECL_THREAD_LOCAL (decl))
+ {
+ warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
+ *no_add_attrs = true;
+ }
+ 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;
+ }
+ }
+
+ return NULL_TREE;
+}
+
+/* Handle a "no_instrument_function" attribute; arguments as in
+ struct attribute_spec.handler. */
+
+static tree
+handle_no_instrument_function_attribute (node, name, args, flags, no_add_attrs)
+ tree *node;
+ tree name;
+ tree args ATTRIBUTE_UNUSED;
+ int flags ATTRIBUTE_UNUSED;
+ bool *no_add_attrs;
+{
+ tree decl = *node;
+
+ if (TREE_CODE (decl) != FUNCTION_DECL)
+ {
+ error_with_decl (decl,
+ "`%s' attribute applies only to functions",
+ IDENTIFIER_POINTER (name));
+ *no_add_attrs = true;
+ }
+ else if (DECL_INITIAL (decl))
+ {
+ error_with_decl (decl,
+ "can't set `%s' attribute after definition",
+ IDENTIFIER_POINTER (name));
+ *no_add_attrs = true;
+ }
+ else
+ DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (decl) = 1;
+
+ return NULL_TREE;
+}
+
+/* Handle a "malloc" attribute; arguments as in
+ struct attribute_spec.handler. */
+
+static tree
+handle_malloc_attribute (node, name, args, flags, no_add_attrs)
+ tree *node;
+ tree name;
+ tree args ATTRIBUTE_UNUSED;
+ int flags ATTRIBUTE_UNUSED;
+ bool *no_add_attrs;
+{
+ if (TREE_CODE (*node) == FUNCTION_DECL)
+ DECL_IS_MALLOC (*node) = 1;
+ /* ??? TODO: Support types. */
+ else
+ {
+ warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
+ *no_add_attrs = true;
+ }
+
+ return NULL_TREE;
+}
+
+/* Handle a "no_limit_stack" attribute; arguments as in
+ struct attribute_spec.handler. */
+
+static tree
+handle_no_limit_stack_attribute (node, name, args, flags, no_add_attrs)
+ tree *node;
+ tree name;
+ tree args ATTRIBUTE_UNUSED;
+ int flags ATTRIBUTE_UNUSED;
+ bool *no_add_attrs;
+{
+ tree decl = *node;
+
+ if (TREE_CODE (decl) != FUNCTION_DECL)
+ {
+ error_with_decl (decl,
+ "`%s' attribute applies only to functions",
+ IDENTIFIER_POINTER (name));
+ *no_add_attrs = true;
+ }
+ else if (DECL_INITIAL (decl))
+ {
+ error_with_decl (decl,
+ "can't set `%s' attribute after definition",
+ IDENTIFIER_POINTER (name));
+ *no_add_attrs = true;
+ }
+ else
+ DECL_NO_LIMIT_STACK (decl) = 1;
+
+ return NULL_TREE;
+}
+
+/* Handle a "pure" attribute; arguments as in
+ struct attribute_spec.handler. */
+
+static tree
+handle_pure_attribute (node, name, args, flags, no_add_attrs)
+ tree *node;
+ tree name;
+ tree args ATTRIBUTE_UNUSED;
+ int flags ATTRIBUTE_UNUSED;
+ 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));
+ *no_add_attrs = true;
+ }
+
+ return NULL_TREE;
+}
+
+/* Handle a "cleanup" attribute; arguments as in
+ struct attribute_spec.handler. */
+
+static tree
+handle_cleanup_attribute (node, name, args, flags, no_add_attrs)
+ tree *node;
+ tree name;
+ tree args;
+ int flags ATTRIBUTE_UNUSED;
+ bool *no_add_attrs;
+{
+ tree decl = *node;
+ tree cleanup_id, cleanup_decl;
+
+ /* ??? Could perhaps support cleanups on TREE_STATIC, much like we do
+ for global destructors in C++. This requires infrastructure that
+ we don't have generically at the moment. It's also not a feature
+ 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));
+ *no_add_attrs = true;
+ return NULL_TREE;
+ }
+
+ /* Verify that the argument is a function in scope. */
+ /* ??? We could support pointers to functions here as well, if
+ that was considered desirable. */
+ cleanup_id = TREE_VALUE (args);
+ if (TREE_CODE (cleanup_id) != IDENTIFIER_NODE)
+ {
+ error ("cleanup arg 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");
+ *no_add_attrs = true;
+ return NULL_TREE;
+ }
+
+ /* That the function has proper type is checked with the
+ eventual call to build_function_call. */
+
+ return NULL_TREE;
+}
+
+/* Handle a "deprecated" attribute; arguments as in
+ struct attribute_spec.handler. */
+
+static tree
+handle_deprecated_attribute (node, name, args, flags, no_add_attrs)
+ tree *node;
+ tree name;
+ tree args ATTRIBUTE_UNUSED;
+ int flags;
+ bool *no_add_attrs;
+{
+ tree type = NULL_TREE;
+ int warn = 0;
+ const char *what = NULL;
+
+ if (DECL_P (*node))
+ {
+ tree decl = *node;
+ type = TREE_TYPE (decl);
+
+ if (TREE_CODE (decl) == TYPE_DECL
+ || TREE_CODE (decl) == PARM_DECL
+ || TREE_CODE (decl) == VAR_DECL
+ || TREE_CODE (decl) == FUNCTION_DECL
+ || TREE_CODE (decl) == FIELD_DECL)
+ TREE_DEPRECATED (decl) = 1;
+ else
+ warn = 1;
+ }
+ else if (TYPE_P (*node))
+ {
+ if (!(flags & (int) ATTR_FLAG_TYPE_IN_PLACE))
+ *node = build_type_copy (*node);
+ TREE_DEPRECATED (*node) = 1;
+ type = *node;
+ }
+ else
+ warn = 1;
+
+ if (warn)
+ {
+ *no_add_attrs = true;
+ if (type && TYPE_NAME (type))
+ {
+ if (TREE_CODE (TYPE_NAME (type)) == IDENTIFIER_NODE)
+ what = IDENTIFIER_POINTER (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)));
+ }
+ if (what)
+ warning ("`%s' attribute ignored for `%s'",
+ IDENTIFIER_POINTER (name), what);
+ else
+ warning ("`%s' attribute ignored",
+ IDENTIFIER_POINTER (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 (node, name, args, flags, no_add_attrs)
+ tree *node;
+ tree name;
+ tree args;
+ int flags ATTRIBUTE_UNUSED;
+ 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;
+
+ *no_add_attrs = true;
+
+ if (! host_integerp (TREE_VALUE (args), 1))
+ {
+ warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
+ return NULL_TREE;
+ }
+
+ /* Get the vector size (in bytes). */
+ vecsize = tree_low_cst (TREE_VALUE (args), 1);
+
+ /* We need to provide for vector pointers, vector arrays, and
+ functions returning vectors. For example:
+
+ __attribute__((vector_size(16))) short *foo;
+
+ In this case, the mode is SI, but the type being modified is
+ HI, so we need to look further. */
+
+ while (POINTER_TYPE_P (type)
+ || TREE_CODE (type) == FUNCTION_TYPE
+ || TREE_CODE (type) == ARRAY_TYPE)
+ type = TREE_TYPE (type);
+
+ /* Get the mode of the type being modified. */
+ orig_mode = TYPE_MODE (type);
+
+ if (TREE_CODE (type) == RECORD_TYPE
+ || (GET_MODE_CLASS (orig_mode) != MODE_FLOAT
+ && GET_MODE_CLASS (orig_mode) != MODE_INT)
+ || ! host_integerp (TYPE_SIZE_UNIT (type), 1))
+ {
+ error ("invalid vector type for attribute `%s'",
+ IDENTIFIER_POINTER (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)
+ {
+ error ("no vector mode with the size and type specified could be found");
+ return NULL_TREE;
+ }
+
+ for (type_list_node = vector_type_node_list; type_list_node;
+ type_list_node = TREE_CHAIN (type_list_node))
+ {
+ 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;
+ }
+ }
+
+ if (new_type == NULL_TREE)
+ {
+ 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;
+ }
+
+ /* Build back pointers if needed. */
+ *node = vector_size_helper (*node, new_type);
+
+ return NULL_TREE;
+}
+
+/* HACK. GROSS. This is absolutely disgusting. I wish there was a
+ better way.
+
+ If we requested a pointer to a vector, build up the pointers that
+ we stripped off while looking for the inner type. Similarly for
+ return values from functions.
+
+ The argument "type" is the top of the chain, and "bottom" is the
+ new type which we will point to. */
+
+static tree
+vector_size_helper (type, bottom)
+ tree type, bottom;
+{
+ tree inner, outer;
+
+ if (POINTER_TYPE_P (type))
+ {
+ inner = vector_size_helper (TREE_TYPE (type), bottom);
+ outer = build_pointer_type (inner);
+ }
+ else if (TREE_CODE (type) == ARRAY_TYPE)
+ {
+ inner = vector_size_helper (TREE_TYPE (type), bottom);
+ outer = build_array_type (inner, TYPE_VALUES (type));
+ }
+ else if (TREE_CODE (type) == FUNCTION_TYPE)
+ {
+ inner = vector_size_helper (TREE_TYPE (type), bottom);
+ outer = build_function_type (inner, TYPE_VALUES (type));
+ }
+ else
+ return bottom;
+
+ TREE_READONLY (outer) = TREE_READONLY (type);
+ TREE_THIS_VOLATILE (outer) = TREE_THIS_VOLATILE (type);
+
+ return outer;
+}
+
+/* Handle the "nonnull" attribute. */
+static tree
+handle_nonnull_attribute (node, name, args, flags, no_add_attrs)
+ tree *node;
+ tree name ATTRIBUTE_UNUSED;
+ tree args;
+ int flags ATTRIBUTE_UNUSED;
+ bool *no_add_attrs;
+{
+ tree type = *node;
+ unsigned HOST_WIDE_INT attr_arg_num;
+
+ /* If no arguments are specified, all pointer arguments should be
+ non-null. Veryify a full prototype is given so that the arguments
+ will have the correct types when we actually check them later. */
+ if (! args)
+ {
+ if (! TYPE_ARG_TYPES (type))
+ {
+ error ("nonnull attribute without arguments on a non-prototype");
+ *no_add_attrs = true;
+ }
+ return NULL_TREE;
+ }
+
+ /* Argument list specified. Verify that each argument number references
+ a pointer argument. */
+ for (attr_arg_num = 1; args; args = TREE_CHAIN (args))
+ {
+ tree argument;
+ unsigned HOST_WIDE_INT arg_num, ck_num;
+
+ if (! get_nonnull_operand (TREE_VALUE (args), &arg_num))
+ {
+ error ("nonnull argument has invalid operand number (arg %lu)",
+ (unsigned long) attr_arg_num);
+ *no_add_attrs = true;
+ return NULL_TREE;
+ }
+
+ argument = TYPE_ARG_TYPES (type);
+ if (argument)
+ {
+ for (ck_num = 1; ; ck_num++)
+ {
+ if (! argument || ck_num == arg_num)
+ break;
+ argument = TREE_CHAIN (argument);
+ }
+
+ if (! argument
+ || TREE_CODE (TREE_VALUE (argument)) == VOID_TYPE)
+ {
+ error ("nonnull argument with out-of-range operand number (arg %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)
+ {
+ error ("nonnull argument references non-pointer operand (arg %lu, operand %lu)",
+ (unsigned long) attr_arg_num, (unsigned long) arg_num);
+ *no_add_attrs = true;
+ return NULL_TREE;
+ }
+ }
+ }
+
+ return NULL_TREE;
+}
+
+/* Check the argument list of a function call for null in argument slots
+ that are marked as requiring a non-null pointer argument. */
+
+static void
+check_function_nonnull (attrs, params)
+ tree attrs;
+ tree params;
+{
+ tree a, args, param;
+ int param_num;
+
+ for (a = attrs; a; a = TREE_CHAIN (a))
+ {
+ if (is_attribute_p ("nonnull", TREE_PURPOSE (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
+ for pointer type is done in check_nonnull_arg). */
+ for (param = params, param_num = 1; ;
+ param_num++, param = TREE_CHAIN (param))
+ {
+ if (! param)
+ break;
+ if (! args || nonnull_check_p (args, param_num))
+ check_function_arguments_recurse (check_nonnull_arg, NULL,
+ TREE_VALUE (param),
+ param_num);
+ }
+ }
+ }
+}
+
+/* Helper for check_function_nonnull; given a list of operands which
+ must be non-null in ARGS, determine if operand PARAM_NUM should be
+ checked. */
+
+static bool
+nonnull_check_p (args, param_num)
+ tree args;
+ unsigned HOST_WIDE_INT param_num;
+{
+ unsigned HOST_WIDE_INT arg_num;
+
+ for (; args; args = TREE_CHAIN (args))
+ {
+ if (! get_nonnull_operand (TREE_VALUE (args), &arg_num))
+ abort ();
+
+ if (arg_num == param_num)
+ return true;
+ }
+ return false;
+}
+
+/* Check that the function argument PARAM (which is operand number
+ PARAM_NUM) is non-null. This is called by check_function_nonnull
+ via check_function_arguments_recurse. */
+
+static void
+check_nonnull_arg (ctx, param, param_num)
+ void *ctx ATTRIBUTE_UNUSED;
+ tree param;
+ unsigned HOST_WIDE_INT param_num;
+{
+ /* Just skip checking the argument if it's not a pointer. This can
+ happen if the "nonnull" attribute was given without an operand
+ list (which means to check every pointer argument). */
+
+ if (TREE_CODE (TREE_TYPE (param)) != POINTER_TYPE)
+ return;
+
+ if (integer_zerop (param))
+ warning ("null argument where non-null required (arg %lu)",
+ (unsigned long) param_num);
+}
+
+/* Helper for nonnull attribute handling; fetch the operand number
+ from the attribute argument list. */
+
+static bool
+get_nonnull_operand (arg_num_expr, valp)
+ 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);
+
+ if (TREE_CODE (arg_num_expr) != INTEGER_CST
+ || TREE_INT_CST_HIGH (arg_num_expr) != 0)
+ return false;
+
+ *valp = TREE_INT_CST_LOW (arg_num_expr);
+ return true;
+}
+
+/* Handle a "nothrow" attribute; arguments as in
+ struct attribute_spec.handler. */
+
+static tree
+handle_nothrow_attribute (node, name, args, flags, no_add_attrs)
+ tree *node;
+ tree name;
+ tree args ATTRIBUTE_UNUSED;
+ int flags ATTRIBUTE_UNUSED;
+ 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));
+ *no_add_attrs = true;
+ }
+
+ return NULL_TREE;
+}
+
+/* Check for valid arguments being passed to a function. */
+void
+check_function_arguments (attrs, params)
+ tree attrs;
+ tree params;
+{
+ /* 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. */
+
+ if (warn_nonnull)
+ check_function_nonnull (attrs, params);
+
+ /* Check for errors in format strings. */
+
+ if (warn_format)
+ check_function_format (NULL, attrs, params);
+}
+
+/* Generic argument checking recursion routine. PARAM is the argument to
+ be checked. PARAM_NUM is the number of the argument. CALLBACK is invoked
+ once the argument is resolved. CTX is context for the callback. */
+void
+check_function_arguments_recurse (callback, ctx, param, param_num)
+ void (*callback) PARAMS ((void *, tree, unsigned HOST_WIDE_INT));
+ void *ctx;
+ tree param;
+ unsigned HOST_WIDE_INT param_num;
+{
+ if (TREE_CODE (param) == NOP_EXPR)
+ {
+ /* Strip coercion. */
+ check_function_arguments_recurse (callback, ctx,
+ TREE_OPERAND (param, 0), param_num);
+ return;
+ }
+
+ if (TREE_CODE (param) == CALL_EXPR)
+ {
+ tree type = TREE_TYPE (TREE_TYPE (TREE_OPERAND (param, 0)));
+ tree attrs;
+ bool found_format_arg = false;
+
+ /* See if this is a call to a known internationalization function
+ that modifies a format arg. Such a function may have multiple
+ format_arg attributes (for example, ngettext). */
+
+ for (attrs = TYPE_ATTRIBUTES (type);
+ attrs;
+ attrs = TREE_CHAIN (attrs))
+ if (is_attribute_p ("format_arg", TREE_PURPOSE (attrs)))
+ {
+ tree inner_args;
+ tree format_num_expr;
+ int format_num;
+ int i;
+
+ /* 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 ();
+
+ format_num = TREE_INT_CST_LOW (format_num_expr);
+
+ for (inner_args = TREE_OPERAND (param, 1), i = 1;
+ inner_args != 0;
+ inner_args = TREE_CHAIN (inner_args), i++)
+ if (i == format_num)
+ {
+ check_function_arguments_recurse (callback, ctx,
+ TREE_VALUE (inner_args),
+ param_num);
+ found_format_arg = true;
+ break;
+ }
+ }
+
+ /* If we found a format_arg attribute and did a recursive check,
+ we are done with checking this argument. Otherwise, we continue
+ and this will be considered a non-literal. */
+ if (found_format_arg)
+ return;
+ }
+
+ if (TREE_CODE (param) == COND_EXPR)
+ {
+ /* Check both halves of the conditional expression. */
+ check_function_arguments_recurse (callback, ctx,
+ TREE_OPERAND (param, 1), param_num);
+ check_function_arguments_recurse (callback, ctx,
+ TREE_OPERAND (param, 2), param_num);
+ return;
+ }
+
+ (*callback) (ctx, param, param_num);
+}
+
+#include "gt-c-common.h"
OpenPOWER on IntegriCloud