diff options
author | kan <kan@FreeBSD.org> | 2003-07-11 04:00:23 +0000 |
---|---|---|
committer | kan <kan@FreeBSD.org> | 2003-07-11 04:00:23 +0000 |
commit | 4e7ac24200e18bbd6367139a46c1286294a70474 (patch) | |
tree | c567c233a70a71a655646549c59efb4bd5c61d04 /contrib/gcc/c-common.c | |
parent | b664230ac178e69c3c146968ee0c3300a4009f60 (diff) | |
download | FreeBSD-src-4e7ac24200e18bbd6367139a46c1286294a70474.zip FreeBSD-src-4e7ac24200e18bbd6367139a46c1286294a70474.tar.gz |
FreeBSD uses stock versions of these GCC files.
Diffstat (limited to 'contrib/gcc/c-common.c')
-rw-r--r-- | contrib/gcc/c-common.c | 3549 |
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" |