/* Subroutines shared by all languages that are variants of C.
Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000,
- 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
+ 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
This file is part of GCC.
#include "toplev.h"
#include "tree-iterator.h"
#include "hashtab.h"
+#include "tree-mudflap.h"
+#include "opts.h"
+#include "real.h"
cpp_reader *parse_in; /* Declared in c-pragma.h. */
/* 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
- (in which case -Wextra gets to decide). */
-
-int warn_sign_compare = -1;
-
-/* Nonzero means warn about usage of long long when `-pedantic'. */
-
-int warn_long_long = 1;
/* Nonzero means warn about deprecated conversion from string constant to
`char *'. */
int warn_write_strings;
-/* Nonzero means warn about multiple (redundant) decls for the same single
- variable or function. */
-
-int warn_redundant_decls;
-
-/* Warn about testing equality of floating point numbers. */
-
-int warn_float_equal;
-
-/* Warn about a subscript that has type char. */
-
-int warn_char_subscripts;
-
-/* Warn if a type conversion is done that might have confusing results. */
-
-int warn_conversion;
-
/* Warn about #pragma directives that are not recognized. */
int warn_unknown_pragmas; /* Tri state variable. */
int warn_format;
-/* Warn about Y2K problems with strftime formats. */
-
-int warn_format_y2k;
-
-/* Warn about excess arguments to formats. */
-
-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;
-
/* Zero means that faster, ...NonNil variants of objc_msgSend...
calls will be used in ObjC; passing nil receivers to such calls
will most likely result in crashes. */
unit. It will inform the ObjC runtime that class definition(s) herein
contained are to replace one(s) previously loaded. */
int flag_replace_objc_classes = 0;
-
-/* C/ObjC language option variables. */
-
-/* Nonzero means message about use of implicit function declarations;
- 1 means warning; 2 means error. */
+/* C/ObjC language option variables. */
-int mesg_implicit_function_declaration = -1;
/* Nonzero means allow type mismatches in conditional expressions;
just make their values `void'. */
int flag_hosted = 1;
-/* Nonzero means warn when casting a function call to a type that does
- not match the return type (e.g. (float)sqrt() or (anything*)malloc()
- when there is no previous declaration of sqrt or malloc. */
-
-int warn_bad_function_cast;
-
-/* Warn about traditional constructs whose meanings changed in ANSI C. */
-
-int warn_traditional;
-
-/* Nonzero means warn for a declaration found after a statement. */
-
-int warn_declaration_after_statement;
-
-/* Nonzero means warn for non-prototype function decls
- or non-prototyped defs without previous prototype. */
-
-int warn_strict_prototypes;
-
-/* Nonzero means warn for any global function def
- without separate previous decl. */
-
-int warn_missing_declarations;
-
-/* Nonzero means warn about declarations of objects not at
- file-scope level and about *all* declarations of functions (whether
- or static) not at file-scope level. Note that we exclude
- implicit function declarations. To get warnings about those, use
- -Wimplicit. */
-
-int warn_nested_externs;
-
/* Warn if main is suspicious. */
int warn_main;
-/* Nonzero means warn about possible violations of sequence point rules. */
-
-int warn_sequence_point;
-
-/* Nonzero means warn about uninitialized variable when it is initialized with itself.
- For example: int i = i;, GCC will not warn about this when warn_init_self is nonzero. */
-
-int warn_init_self;
-
-/* Nonzero means to warn about compile-time division by zero. */
-int warn_div_by_zero = 1;
-
-/* Nonzero means warn about use of implicit int. */
-
-int warn_implicit_int;
-
-/* Warn about NULL being passed to argument slots marked as requiring
- non-NULL. */
-
-int warn_nonnull;
-
-/* Warn about old-style parameter declaration. */
-
-int warn_old_style_definition;
-
/* ObjC language option variables. */
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. */
int flag_enforce_eh_specs = 1;
-/* Nonzero means warn about things that will change when compiling
- with an ABI-compliant compiler. */
-
-int warn_abi = 0;
-
-/* Nonzero means warn about invalid uses of offsetof. */
+/* Nonzero means to generate thread-safe code for initializing local
+ statics. */
-int warn_invalid_offsetof = 1;
+int flag_threadsafe_statics = 1;
/* Nonzero means warn about implicit declarations. */
int warn_implicit = 1;
-/* Nonzero means warn when all ctors or dtors are private, and the class
- has no friends. */
-
-int warn_ctor_dtor_privacy = 0;
-
-/* Nonzero means warn in function declared in derived class has the
- same name as a virtual in the base class, but fails to match the
- type signature of any virtual function in the base class. */
-
-int warn_overloaded_virtual;
-
-/* Nonzero means warn when declaring a class that has a non virtual
- destructor, when it really ought to have a virtual one. */
-
-int warn_nonvdtor;
-
-/* Nonzero means warn when the compiler will reorder code. */
-
-int warn_reorder;
-
-/* Nonzero means warn when synthesis behavior differs from Cfront's. */
-
-int warn_synth;
-
-/* Nonzero means warn when we convert a pointer to member function
- into a pointer to (void or function). */
-
-int warn_pmf2ptr = 1;
-
-/* Nonzero means warn about violation of some Effective C++ style rules. */
-
-int warn_ecpp;
-
-/* Nonzero means warn where overload resolution chooses a promotion from
- unsigned to signed over a conversion to an unsigned of the same size. */
-
-int warn_sign_promo;
-
-/* Nonzero means warn when an old-style cast is used. */
-
-int warn_old_style_cast;
-
-/* Nonzero means warn when non-templatized friend functions are
- declared within a template */
-
-int warn_nontemplate_friend = 1;
-
-/* Nonzero means complain about deprecated features. */
-
-int warn_deprecated = 1;
-
/* Maximum template instantiation depth. This limit is rather
arbitrary, but it exists to limit the time it takes to notice
infinite template instantiations. */
tree (*make_fname_decl) (tree, int);
-/* If non-NULL, the address of a language-specific function that
- returns 1 for language-specific statement codes. */
-int (*lang_statement_code_p) (enum tree_code);
-
-/* If non-NULL, the address of a language-specific function that takes
- any action required right before expand_function_end is called. */
-void (*lang_expand_function_end) (void);
-
/* Nonzero means the expression being parsed will never be evaluated.
This is a count, since unevaluated expressions can nest. */
int skip_evaluation;
};
static int constant_fits_type_p (tree, tree);
+static tree check_case_value (tree);
+static bool check_case_bounds (tree, tree, tree *, tree *);
static tree handle_packed_attribute (tree *, tree, tree, int, bool *);
static tree handle_nocommon_attribute (tree *, tree, tree, int, bool *);
static tree handle_no_instrument_function_attribute (tree *, tree,
tree, int, bool *);
static tree handle_malloc_attribute (tree *, tree, tree, int, bool *);
+static tree handle_returns_twice_attribute (tree *, tree, tree, int, bool *);
static tree handle_no_limit_stack_attribute (tree *, tree, tree, int,
bool *);
static tree handle_pure_attribute (tree *, tree, tree, int, bool *);
+static tree handle_novops_attribute (tree *, tree, tree, int, bool *);
static tree handle_deprecated_attribute (tree *, tree, tree, int,
bool *);
static tree handle_vector_size_attribute (tree *, tree, tree, int,
static tree handle_cleanup_attribute (tree *, tree, tree, int, bool *);
static tree handle_warn_unused_result_attribute (tree *, tree, tree, int,
bool *);
+static tree handle_sentinel_attribute (tree *, tree, tree, int, bool *);
static void check_function_nonnull (tree, tree);
static void check_nonnull_arg (void *, tree, unsigned HOST_WIDE_INT);
handle_no_instrument_function_attribute },
{ "malloc", 0, 0, true, false, false,
handle_malloc_attribute },
+ { "returns_twice", 0, 0, true, false, false,
+ handle_returns_twice_attribute },
{ "no_stack_limit", 0, 0, true, false, false,
handle_no_limit_stack_attribute },
{ "pure", 0, 0, true, false, false,
handle_pure_attribute },
+ /* For internal use (marking of builtins) only. The name contains space
+ to prevent its usage in source code. */
+ { "no vops", 0, 0, true, false, false,
+ handle_novops_attribute },
{ "deprecated", 0, 0, false, false, false,
handle_deprecated_attribute },
{ "vector_size", 1, 1, false, true, false,
handle_vector_size_attribute },
- { "visibility", 1, 1, true, false, false,
+ { "visibility", 1, 1, false, false, false,
handle_visibility_attribute },
{ "tls_model", 1, 1, true, false, false,
handle_tls_model_attribute },
handle_cleanup_attribute },
{ "warn_unused_result", 0, 0, false, true, true,
handle_warn_unused_result_attribute },
+ { "sentinel", 0, 1, false, true, true,
+ handle_sentinel_attribute },
{ NULL, 0, 0, false, false, false, NULL }
};
if (decl)
{
- saved = tree_cons (decl, build_int_2 (ix, 0), saved);
+ saved = tree_cons (decl, build_int_cst (NULL_TREE, ix), saved);
*fname_vars[ix].decl = NULL_TREE;
}
}
char *namep;
int vrb = 2;
- if (! pretty_p)
+ if (!pretty_p)
{
name = "";
vrb = 0;
int len = strlen (name) + 3; /* Two for '"'s. One for NULL. */
cpp_string cstr = { 0, 0 }, strname;
- namep = xmalloc (len);
+ namep = XNEWVEC (char, len);
snprintf (namep, len, "\"%s\"", name);
strname.text = (unsigned char *) namep;
strname.len = len - 1;
if (cpp_interpret_string (parse_in, &strname, 1, &cstr, false))
- return (char *) cstr.text;
+ {
+ XDELETEVEC (namep);
+ return (char *) cstr.text;
+ }
}
else
namep = xstrdup (name);
expand_anon_union_decl (decl, NULL_TREE,
DECL_ANON_UNION_ELEMS (decl));
}
- else if (TREE_CODE (decl) == VAR_DECL && TREE_STATIC (decl))
- make_rtl_for_local_static (decl);
else
return 0;
To avoid this problem set the lineno to 0 here; that prevents
it from appearing in the RTL. */
tree stmts;
- location_t saved_locus = input_location;
+ location_t saved_location = input_location;
+#ifdef USE_MAPPED_LOCATION
+ input_location = UNKNOWN_LOCATION;
+#else
input_line = 0;
+#endif
stmts = push_stmt_list ();
decl = (*make_fname_decl) (id, fname_vars[ix].pretty);
saved_function_name_decls
= tree_cons (decl, stmts, saved_function_name_decls);
*fname_vars[ix].decl = decl;
- input_location = saved_locus;
+ input_location = saved_location;
}
if (!ix && !current_function_decl)
- pedwarn ("%J'%D' is not defined outside of function scope", decl, decl);
+ pedwarn ("%qD is not defined outside of function scope", decl);
return decl;
}
const int nchars_max = flag_isoc99 ? 4095 : 509;
int length = TREE_STRING_LENGTH (value);
int nchars;
+ tree e_type, i_type, a_type;
/* Compute the number of elements, for the array type. */
nchars = wide_flag ? length / wchar_bytes : length;
if (pedantic && nchars - 1 > nchars_max && !c_dialect_cxx ())
- pedwarn ("string length `%d' is greater than the length `%d' ISO C%d compilers are required to support",
+ pedwarn ("string length %qd is greater than the length %qd 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. */
+ e_type = wide_flag ? wchar_type_node : char_type_node;
+ /* Create the array type for the string constant. flag_const_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.
+
+ The C++ front end relies on TYPE_MAIN_VARIANT of a cv-qualified
+ array type being the unqualified version of that type.
+ Therefore, if we are constructing an array of const char, we must
+ construct the matching unqualified array type first. The C front
+ end does not require this, but it does no harm, so we do it
+ unconditionally. */
+ i_type = build_index_type (build_int_cst (NULL_TREE, nchars - 1));
+ a_type = build_array_type (e_type, i_type);
if (flag_const_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)));
+ a_type = c_build_qualified_type (a_type, TYPE_QUAL_CONST);
+ TREE_TYPE (value) = a_type;
TREE_CONSTANT (value) = 1;
TREE_INVARIANT (value) = 1;
TREE_READONLY (value) = 1;
{
return targetm.vector_opaque_p (t1)
|| targetm.vector_opaque_p (t2)
- || TYPE_MODE (t1) == TYPE_MODE (t2);
+ || (tree_int_cst_equal (TYPE_SIZE (t1), TYPE_SIZE (t2))
+ && INTEGRAL_TYPE_P (TREE_TYPE (t1))
+ == INTEGRAL_TYPE_P (TREE_TYPE (t2)));
}
/* Convert EXPR to TYPE, warning about conversion problems with constants.
don't warn unless pedantic. */
if ((pedantic
|| TYPE_UNSIGNED (type)
- || ! constant_fits_type_p (expr,
- c_common_unsigned_type (type)))
+ || !constant_fits_type_p (expr,
+ c_common_unsigned_type (type)))
&& skip_evaluation == 0)
warning ("overflow in implicit constant conversion");
}
new_tlist (struct tlist *next, tree t, tree writer)
{
struct tlist *l;
- l = obstack_alloc (&tlist_obstack, sizeof *l);
+ l = XOBNEW (&tlist_obstack, struct tlist);
l->next = next;
l->expr = t;
l->writer = writer;
while (add)
{
struct tlist *next = add->next;
- if (! copy)
+ if (!copy)
add->next = *to;
- if (! exclude_writer || add->writer != exclude_writer)
+ if (!exclude_writer || add->writer != exclude_writer)
*to = copy ? new_tlist (*to, add->expr, add->writer) : add;
add = next;
}
if (tmp2->expr == add->expr)
{
found = 1;
- if (! tmp2->writer)
+ if (!tmp2->writer)
tmp2->writer = add->writer;
}
- if (! found)
+ if (!found)
{
*end = copy ? add : new_tlist (NULL, add->expr, add->writer);
end = &(*end)->next;
{
if (list->expr == written
&& list->writer != writer
- && (! only_writes || list->writer))
+ && (!only_writes || list->writer)
+ && DECL_NAME (list->expr))
{
warned_ids = new_tlist (warned_ids, written, NULL_TREE);
- warning ("operation on `%s' may be undefined",
- IDENTIFIER_POINTER (DECL_NAME (list->expr)));
+ warning ("operation on %qE may be undefined", list->expr);
}
list = list->next;
}
{
struct tlist *tmp_before, *tmp_nosp, *tmp_list2, *tmp_list3;
enum tree_code code;
- char class;
+ enum tree_code_class cl;
/* X may be NULL if it is the operand of an empty statement expression
({ }). */
restart:
code = TREE_CODE (x);
- class = TREE_CODE_CLASS (code);
+ cl = TREE_CODE_CLASS (code);
if (warning_candidate_p (x))
{
if (t->expr == x)
break;
- if (! t)
+ if (!t)
{
- t = obstack_alloc (&tlist_obstack, sizeof *t);
+ t = XOBNEW (&tlist_obstack, struct tlist_cache);
t->next = save_expr_cache;
t->expr = x;
save_expr_cache = t;
add_tlist (pno_sp, t->cache_after_sp, NULL_TREE, 1);
return;
}
- default:
- break;
- }
-
- if (class == '1')
- {
- if (first_rtl_op (code) == 0)
- return;
- x = TREE_OPERAND (x, 0);
- writer = 0;
- goto restart;
- }
- switch (class)
- {
- case 'r':
- case '<':
- case '2':
- case 'e':
- case 's':
- case 'x':
- {
- int lp;
- int max = first_rtl_op (TREE_CODE (x));
- for (lp = 0; lp < max; lp++)
- {
- tmp_before = tmp_nosp = 0;
- verify_tree (TREE_OPERAND (x, lp), &tmp_before, &tmp_nosp, NULL_TREE);
- merge_tlist (&tmp_nosp, tmp_before, 0);
- add_tlist (pno_sp, tmp_nosp, NULL_TREE, 0);
- }
- break;
- }
+ default:
+ /* For other expressions, simply recurse on their operands.
+ Manual tail recursion for unary expressions.
+ Other non-expressions need not be processed. */
+ if (cl == tcc_unary)
+ {
+ x = TREE_OPERAND (x, 0);
+ writer = 0;
+ goto restart;
+ }
+ else if (IS_EXPR_CODE_CLASS (cl))
+ {
+ int lp;
+ int max = TREE_CODE_LENGTH (TREE_CODE (x));
+ for (lp = 0; lp < max; lp++)
+ {
+ tmp_before = tmp_nosp = 0;
+ verify_tree (TREE_OPERAND (x, lp), &tmp_before, &tmp_nosp, 0);
+ merge_tlist (&tmp_nosp, tmp_before, 0);
+ add_tlist (pno_sp, tmp_nosp, NULL_TREE, 0);
+ }
+ }
+ return;
}
}
if (tlist_firstobj == 0)
{
gcc_obstack_init (&tlist_obstack);
- tlist_firstobj = obstack_alloc (&tlist_obstack, 0);
+ tlist_firstobj = (char *) obstack_alloc (&tlist_obstack, 0);
}
verify_tree (expr, &before_sp, &after_sp, 0);
\f
/* Validate the expression after `case' and apply default promotions. */
-tree
+static tree
check_case_value (tree value)
{
if (value == NULL_TREE)
return value;
- /* Strip NON_LVALUE_EXPRs since we aren't using as an lvalue. */
+ /* ??? Can we ever get nops here for a valid case value? We
+ shouldn't for C. */
STRIP_TYPE_NOPS (value);
/* In C++, the following is allowed:
value = fold (value);
}
- if (TREE_CODE (value) != INTEGER_CST
- && value != error_mark_node)
+ if (TREE_CODE (value) == INTEGER_CST)
+ /* Promote char or short to int. */
+ value = perform_integral_promotions (value);
+ else if (value != error_mark_node)
{
error ("case label does not reduce to an integer constant");
value = error_mark_node;
}
- else
- /* Promote char or short to int. */
- value = default_conversion (value);
constant_expression_warning (value);
return value;
}
\f
+/* See if the case values LOW and HIGH are in the range of the original
+ type (i.e. before the default conversion to int) of the switch testing
+ expression.
+ TYPE is the promoted type of the testing expression, and ORIG_TYPE is
+ the type before promoting it. CASE_LOW_P is a pointer to the lower
+ bound of the case label, and CASE_HIGH_P is the upper bound or NULL
+ if the case is not a case range.
+ The caller has to make sure that we are not called with NULL for
+ CASE_LOW_P (i.e. the default case).
+ Returns true if the case label is in range of ORIG_TYPE (satured or
+ untouched) or false if the label is out of range. */
+
+static bool
+check_case_bounds (tree type, tree orig_type,
+ tree *case_low_p, tree *case_high_p)
+{
+ tree min_value, max_value;
+ tree case_low = *case_low_p;
+ tree case_high = case_high_p ? *case_high_p : case_low;
+
+ /* If there was a problem with the original type, do nothing. */
+ if (orig_type == error_mark_node)
+ return true;
+
+ min_value = TYPE_MIN_VALUE (orig_type);
+ max_value = TYPE_MAX_VALUE (orig_type);
+
+ /* Case label is less than minimum for type. */
+ if (tree_int_cst_compare (case_low, min_value) < 0
+ && tree_int_cst_compare (case_high, min_value) < 0)
+ {
+ warning ("case label value is less than minimum value for type");
+ return false;
+ }
+
+ /* Case value is greater than maximum for type. */
+ if (tree_int_cst_compare (case_low, max_value) > 0
+ && tree_int_cst_compare (case_high, max_value) > 0)
+ {
+ warning ("case label value exceeds maximum value for type");
+ return false;
+ }
+
+ /* Saturate lower case label value to minimum. */
+ if (tree_int_cst_compare (case_high, min_value) >= 0
+ && tree_int_cst_compare (case_low, min_value) < 0)
+ {
+ warning ("lower value in case label range"
+ " less than minimum value for type");
+ case_low = min_value;
+ }
+
+ /* Saturate upper case label value to maximum. */
+ if (tree_int_cst_compare (case_low, max_value) <= 0
+ && tree_int_cst_compare (case_high, max_value) > 0)
+ {
+ warning ("upper value in case label range"
+ " exceeds maximum value for type");
+ case_high = max_value;
+ }
+
+ if (*case_low_p != case_low)
+ *case_low_p = convert (type, case_low);
+ if (case_high_p && *case_high_p != case_high)
+ *case_high_p = convert (type, case_high);
+
+ return true;
+}
+\f
/* Return an integer type with BITS bits of precision,
that is unsigned if UNSIGNEDP is nonzero, otherwise signed. */
if (mode == TYPE_MODE (void_type_node))
return void_type_node;
-
+
if (mode == TYPE_MODE (build_pointer_type (char_type_node)))
- return unsignedp ? make_unsigned_type (mode) : make_signed_type (mode);
+ return (unsignedp
+ ? make_unsigned_type (GET_MODE_PRECISION (mode))
+ : make_signed_type (GET_MODE_PRECISION (mode)));
if (mode == TYPE_MODE (build_pointer_type (integer_type_node)))
- return unsignedp ? make_unsigned_type (mode) : make_signed_type (mode);
+ return (unsignedp
+ ? make_unsigned_type (GET_MODE_PRECISION (mode))
+ : make_signed_type (GET_MODE_PRECISION (mode)));
+
+ if (COMPLEX_MODE_P (mode))
+ {
+ enum machine_mode inner_mode;
+ tree inner_type;
- if (VECTOR_MODE_P (mode))
+ if (mode == TYPE_MODE (complex_float_type_node))
+ return complex_float_type_node;
+ if (mode == TYPE_MODE (complex_double_type_node))
+ return complex_double_type_node;
+ if (mode == TYPE_MODE (complex_long_double_type_node))
+ return complex_long_double_type_node;
+
+ if (mode == TYPE_MODE (complex_integer_type_node) && !unsignedp)
+ return complex_integer_type_node;
+
+ inner_mode = GET_MODE_INNER (mode);
+ inner_type = c_common_type_for_mode (inner_mode, unsignedp);
+ if (inner_type != NULL_TREE)
+ return build_complex_type (inner_type);
+ }
+ else if (VECTOR_MODE_P (mode))
{
enum machine_mode inner_mode = GET_MODE_INNER (mode);
tree inner_type = c_common_type_for_mode (inner_mode, unsignedp);
tree
c_common_signed_or_unsigned_type (int unsignedp, tree type)
{
- if (! INTEGRAL_TYPE_P (type)
+ if (!INTEGRAL_TYPE_P (type)
|| TYPE_UNSIGNED (type) == unsignedp)
return type;
- /* Must check the mode of the types, not the precision. Enumeral types
- in C++ have precision set to match their range, but may use a wider
- mode to match an ABI. If we change modes, we may wind up with bad
- conversions. */
-
- if (TYPE_MODE (type) == TYPE_MODE (signed_char_type_node))
+ /* For ENUMERAL_TYPEs in C++, must check the mode of the types, not
+ the precision; they have precision set to match their range, but
+ may use a wider mode to match an ABI. If we change modes, we may
+ wind up with bad conversions. For INTEGER_TYPEs in C, must check
+ the precision as well, so as to yield correct results for
+ bit-field types. C++ does not have these separate bit-field
+ types, and producing a signed or unsigned variant of an
+ ENUMERAL_TYPE may cause other problems as well. */
+
+#define TYPE_OK(node) \
+ (TYPE_MODE (type) == TYPE_MODE (node) \
+ && (c_dialect_cxx () || TYPE_PRECISION (type) == TYPE_PRECISION (node)))
+ if (TYPE_OK (signed_char_type_node))
return unsignedp ? unsigned_char_type_node : signed_char_type_node;
- if (TYPE_MODE (type) == TYPE_MODE (integer_type_node))
+ if (TYPE_OK (integer_type_node))
return unsignedp ? unsigned_type_node : integer_type_node;
- if (TYPE_MODE (type) == TYPE_MODE (short_integer_type_node))
+ if (TYPE_OK (short_integer_type_node))
return unsignedp ? short_unsigned_type_node : short_integer_type_node;
- if (TYPE_MODE (type) == TYPE_MODE (long_integer_type_node))
+ if (TYPE_OK (long_integer_type_node))
return unsignedp ? long_unsigned_type_node : long_integer_type_node;
- if (TYPE_MODE (type) == TYPE_MODE (long_long_integer_type_node))
+ if (TYPE_OK (long_long_integer_type_node))
return (unsignedp ? long_long_unsigned_type_node
: long_long_integer_type_node);
- if (TYPE_MODE (type) == TYPE_MODE (widest_integer_literal_type_node))
+ if (TYPE_OK (widest_integer_literal_type_node))
return (unsignedp ? widest_unsigned_literal_type_node
: widest_integer_literal_type_node);
#if HOST_BITS_PER_WIDE_INT >= 64
- if (TYPE_MODE (type) == TYPE_MODE (intTI_type_node))
+ if (TYPE_OK (intTI_type_node))
return unsignedp ? unsigned_intTI_type_node : intTI_type_node;
#endif
- if (TYPE_MODE (type) == TYPE_MODE (intDI_type_node))
+ if (TYPE_OK (intDI_type_node))
return unsignedp ? unsigned_intDI_type_node : intDI_type_node;
- if (TYPE_MODE (type) == TYPE_MODE (intSI_type_node))
+ if (TYPE_OK (intSI_type_node))
return unsignedp ? unsigned_intSI_type_node : intSI_type_node;
- if (TYPE_MODE (type) == TYPE_MODE (intHI_type_node))
+ if (TYPE_OK (intHI_type_node))
return unsignedp ? unsigned_intHI_type_node : intHI_type_node;
- if (TYPE_MODE (type) == TYPE_MODE (intQI_type_node))
+ if (TYPE_OK (intQI_type_node))
return unsignedp ? unsigned_intQI_type_node : intQI_type_node;
+#undef TYPE_OK
- return type;
+ if (c_dialect_cxx ())
+ return type;
+ else
+ return build_nonstandard_integer_type (TYPE_PRECISION (type), unsignedp);
}
/* The C version of the register_builtin_type langhook. */
else
log = tree_floor_log2 (value);
- return log + 1 + ! unsignedp;
+ return log + 1 + !unsignedp;
}
\f
/* Print an error message for invalid operands to arith operation
opname = "||"; break;
case BIT_XOR_EXPR:
opname = "^"; break;
- case LROTATE_EXPR:
- case RROTATE_EXPR:
- opname = "rotate"; break;
default:
- opname = "unknown"; break;
+ gcc_unreachable ();
}
error ("invalid operands to binary %s", opname);
}
the second arg is 0. */
if (TREE_CONSTANT (primop0)
- && ! integer_zerop (primop1) && ! real_zerop (primop1))
+ && !integer_zerop (primop1) && !real_zerop (primop1))
{
tree tem = primop0;
int temi = unsignedp0;
type = c_common_signed_or_unsigned_type (unsignedp0,
TREE_TYPE (primop0));
- /* In C, if TYPE is an enumeration, then we need to get its
- min/max values from its underlying integral type, not the
- enumerated type itself. In C++, TYPE_MAX_VALUE and
- TYPE_MIN_VALUE have already been set correctly on the
- enumeration type. */
- if (!c_dialect_cxx() && TREE_CODE (type) == ENUMERAL_TYPE)
- type = c_common_type_for_size (TYPE_PRECISION (type), unsignedp0);
-
maxval = TYPE_MAX_VALUE (type);
minval = TYPE_MIN_VALUE (type);
*restype_ptr = c_common_signed_type (*restype_ptr);
if (TREE_TYPE (primop1) != *restype_ptr)
- primop1 = convert (*restype_ptr, primop1);
+ {
+ /* Convert primop1 to target type, but do not introduce
+ additional overflow. We know primop1 is an int_cst. */
+ tree tmp = build_int_cst_wide (*restype_ptr,
+ TREE_INT_CST_LOW (primop1),
+ TREE_INT_CST_HIGH (primop1));
+
+ primop1 = force_fit_type (tmp, 0, TREE_OVERFLOW (primop1),
+ TREE_CONSTANT_OVERFLOW (primop1));
+ }
if (type != *restype_ptr)
{
minval = convert (*restype_ptr, minval);
{
/* Don't forget to evaluate PRIMOP0 if it has side effects. */
if (TREE_SIDE_EFFECTS (primop0))
- return build (COMPOUND_EXPR, TREE_TYPE (val), primop0, val);
+ return build2 (COMPOUND_EXPR, TREE_TYPE (val), primop0, val);
return val;
}
>= 0, the signedness of the comparison isn't an issue,
so suppress the warning. */
if (extra_warnings && !in_system_header
- && ! (TREE_CODE (primop0) == INTEGER_CST
- && ! TREE_OVERFLOW (convert (c_common_signed_type (type),
- primop0))))
+ && !(TREE_CODE (primop0) == INTEGER_CST
+ && !TREE_OVERFLOW (convert (c_common_signed_type (type),
+ primop0))))
warning ("comparison of unsigned expression >= 0 is always true");
value = truthvalue_true_node;
break;
case LT_EXPR:
if (extra_warnings && !in_system_header
- && ! (TREE_CODE (primop0) == INTEGER_CST
- && ! TREE_OVERFLOW (convert (c_common_signed_type (type),
- primop0))))
+ && !(TREE_CODE (primop0) == INTEGER_CST
+ && !TREE_OVERFLOW (convert (c_common_signed_type (type),
+ primop0))))
warning ("comparison of unsigned expression < 0 is always false");
value = truthvalue_false_node;
break;
{
/* Don't forget to evaluate PRIMOP0 if it has side effects. */
if (TREE_SIDE_EFFECTS (primop0))
- return build (COMPOUND_EXPR, TREE_TYPE (value),
- primop0, value);
+ return build2 (COMPOUND_EXPR, TREE_TYPE (value),
+ primop0, value);
return value;
}
}
if (TREE_CODE (TREE_TYPE (result_type)) == VOID_TYPE)
{
if (pedantic || warn_pointer_arith)
- pedwarn ("pointer of type `void *' used in arithmetic");
+ pedwarn ("pointer of type %<void *%> used in arithmetic");
size_exp = integer_one_node;
}
else if (TREE_CODE (TREE_TYPE (result_type)) == FUNCTION_TYPE)
This helps produce common subexpressions. */
if ((TREE_CODE (intop) == PLUS_EXPR || TREE_CODE (intop) == MINUS_EXPR)
- && ! TREE_CONSTANT (intop)
+ && !TREE_CONSTANT (intop)
&& TREE_CONSTANT (TREE_OPERAND (intop, 1))
&& TREE_CONSTANT (size_exp)
/* If the constant comes from pointer subtraction,
/* If the constant is unsigned, and smaller than the pointer size,
then we must skip this optimization. This is because it could cause
an overflow error if the constant is negative but INTOP is not. */
- && (! TYPE_UNSIGNED (TREE_TYPE (intop))
+ && (!TYPE_UNSIGNED (TREE_TYPE (intop))
|| (TYPE_PRECISION (TREE_TYPE (intop))
== TYPE_PRECISION (TREE_TYPE (ptrop)))))
{
convert (TREE_TYPE (intop), size_exp), 1));
/* Create the sum or difference. */
- return fold (build (resultcode, result_type, ptrop, intop));
+ return fold (build2 (resultcode, result_type, ptrop, intop));
}
\f
/* Prepare expr to be an argument of a TRUTH_NOT_EXPR,
- or validate its data type for an `if' or `while' statement or ?..: exp.
+ or for an `if' or `while' statement or ?..: exp. It should already
+ have been validated to be of suitable type; otherwise, a bad
+ diagnostic may result.
This preparation consists of taking the ordinary
representation of an expression expr and producing a valid tree
tree
c_common_truthvalue_conversion (tree expr)
{
- if (TREE_CODE (expr) == ERROR_MARK)
- return expr;
-
- if (TREE_CODE (expr) == FUNCTION_DECL)
- expr = build_unary_op (ADDR_EXPR, expr, 0);
-
switch (TREE_CODE (expr))
{
case EQ_EXPR: case NE_EXPR: case UNEQ_EXPR: case LTGT_EXPR:
case LE_EXPR: case GE_EXPR: case LT_EXPR: case GT_EXPR:
case UNLE_EXPR: case UNGE_EXPR: case UNLT_EXPR: case UNGT_EXPR:
case ORDERED_EXPR: case UNORDERED_EXPR:
+ if (TREE_TYPE (expr) == truthvalue_type_node)
+ return expr;
+ return build2 (TREE_CODE (expr), truthvalue_type_node,
+ TREE_OPERAND (expr, 0), TREE_OPERAND (expr, 1));
+
case TRUTH_ANDIF_EXPR:
case TRUTH_ORIF_EXPR:
case TRUTH_AND_EXPR:
case TRUTH_OR_EXPR:
case TRUTH_XOR_EXPR:
+ if (TREE_TYPE (expr) == truthvalue_type_node)
+ return expr;
+ return build2 (TREE_CODE (expr), truthvalue_type_node,
+ c_common_truthvalue_conversion (TREE_OPERAND (expr, 0)),
+ c_common_truthvalue_conversion (TREE_OPERAND (expr, 1)));
+
case TRUTH_NOT_EXPR:
- TREE_TYPE (expr) = truthvalue_type_node;
- return expr;
+ if (TREE_TYPE (expr) == truthvalue_type_node)
+ return expr;
+ return build1 (TREE_CODE (expr), truthvalue_type_node,
+ c_common_truthvalue_conversion (TREE_OPERAND (expr, 0)));
case ERROR_MARK:
return expr;
case INTEGER_CST:
- return integer_zerop (expr) ? truthvalue_false_node : truthvalue_true_node;
+ /* Avoid integer_zerop to ignore TREE_CONSTANT_OVERFLOW. */
+ return (TREE_INT_CST_LOW (expr) != 0 || TREE_INT_CST_HIGH (expr) != 0)
+ ? truthvalue_true_node
+ : truthvalue_false_node;
case REAL_CST:
- return real_zerop (expr) ? truthvalue_false_node : truthvalue_true_node;
+ return real_compare (NE_EXPR, &TREE_REAL_CST (expr), &dconst0)
+ ? truthvalue_true_node
+ : truthvalue_false_node;
+
+ case FUNCTION_DECL:
+ expr = build_unary_op (ADDR_EXPR, expr, 0);
+ /* Fall through. */
case ADDR_EXPR:
{
if (TREE_CODE (TREE_OPERAND (expr, 0)) == FUNCTION_DECL
- && ! DECL_WEAK (TREE_OPERAND (expr, 0)))
+ && !DECL_WEAK (TREE_OPERAND (expr, 0)))
{
/* Common Ada/Pascal programmer's mistake. We always warn
about this since it is so bad. */
- warning ("the address of `%D', will always evaluate as `true'",
+ warning ("the address of %qD, will always evaluate as %<true%>",
TREE_OPERAND (expr, 0));
return truthvalue_true_node;
}
break;
if (TREE_SIDE_EFFECTS (TREE_OPERAND (expr, 0)))
- return build (COMPOUND_EXPR, truthvalue_type_node,
- TREE_OPERAND (expr, 0), truthvalue_true_node);
+ return build2 (COMPOUND_EXPR, truthvalue_type_node,
+ TREE_OPERAND (expr, 0), truthvalue_true_node);
else
return truthvalue_true_node;
}
case COMPLEX_EXPR:
return build_binary_op ((TREE_SIDE_EFFECTS (TREE_OPERAND (expr, 1))
? TRUTH_OR_EXPR : TRUTH_ORIF_EXPR),
- lang_hooks.truthvalue_conversion (TREE_OPERAND (expr, 0)),
- lang_hooks.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:
/* These don't change whether an object is nonzero or zero. */
- return lang_hooks.truthvalue_conversion (TREE_OPERAND (expr, 0));
+ 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 nonzero, but
we can't ignore them if their second arg has side-effects. */
if (TREE_SIDE_EFFECTS (TREE_OPERAND (expr, 1)))
- return build (COMPOUND_EXPR, truthvalue_type_node, TREE_OPERAND (expr, 1),
- lang_hooks.truthvalue_conversion (TREE_OPERAND (expr, 0)));
+ return build2 (COMPOUND_EXPR, truthvalue_type_node,
+ TREE_OPERAND (expr, 1),
+ c_common_truthvalue_conversion (TREE_OPERAND (expr, 0)));
else
- return lang_hooks.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, truthvalue_type_node, TREE_OPERAND (expr, 0),
- lang_hooks.truthvalue_conversion (TREE_OPERAND (expr, 1)),
- lang_hooks.truthvalue_conversion (TREE_OPERAND (expr, 2))));
+ return fold (build3 (COND_EXPR, truthvalue_type_node,
+ TREE_OPERAND (expr, 0),
+ c_common_truthvalue_conversion (TREE_OPERAND (expr, 1)),
+ c_common_truthvalue_conversion (TREE_OPERAND (expr, 2))));
case CONVERT_EXPR:
/* Don't cancel the effect of a CONVERT_EXPR from a REFERENCE_TYPE,
/* 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 lang_hooks.truthvalue_conversion (TREE_OPERAND (expr, 0));
+ return c_common_truthvalue_conversion (TREE_OPERAND (expr, 0));
break;
case MINUS_EXPR:
break;
case MODIFY_EXPR:
- if (warn_parentheses && C_EXP_ORIGINAL_CODE (expr) == MODIFY_EXPR)
+ if (warn_parentheses && !TREE_NO_WARNING (expr))
warning ("suggest parentheses around assignment used as truth value");
break;
return (build_binary_op
((TREE_SIDE_EFFECTS (expr)
? TRUTH_OR_EXPR : TRUTH_ORIF_EXPR),
- lang_hooks.truthvalue_conversion (build_unary_op (REALPART_EXPR, t, 0)),
- lang_hooks.truthvalue_conversion (build_unary_op (IMAGPART_EXPR, t, 0)),
+ c_common_truthvalue_conversion (build_unary_op (REALPART_EXPR, t, 0)),
+ c_common_truthvalue_conversion (build_unary_op (IMAGPART_EXPR, t, 0)),
0));
}
return build_binary_op (NE_EXPR, expr, integer_zero_node, 1);
}
\f
-static tree builtin_function_2 (const char *, const char *, tree, tree,
- int, enum built_in_class, int, int,
- tree);
+static tree builtin_function_2 (const char *builtin_name, const char *name,
+ tree builtin_type, tree type,
+ enum built_in_function function_code,
+ enum built_in_class cl, int library_name_p,
+ bool nonansi_p,
+ tree attrs);
/* Make a variant type in the proper way for C/C++, propagating qualifiers
down to the element type of an array. */
{
if (type == error_mark_node)
return type;
-
+
if (TREE_CODE (type) == ARRAY_TYPE)
- return build_array_type (c_build_qualified_type (TREE_TYPE (type),
- type_quals),
- TYPE_DOMAIN (type));
+ {
+ tree t;
+ tree element_type = c_build_qualified_type (TREE_TYPE (type),
+ type_quals);
+
+ /* See if we already have an identically qualified type. */
+ for (t = TYPE_MAIN_VARIANT (type); t; t = TYPE_NEXT_VARIANT (t))
+ {
+ if (TYPE_QUALS (strip_array_types (t)) == type_quals
+ && TYPE_NAME (t) == TYPE_NAME (type)
+ && TYPE_CONTEXT (t) == TYPE_CONTEXT (type)
+ && attribute_list_equal (TYPE_ATTRIBUTES (t),
+ TYPE_ATTRIBUTES (type)))
+ break;
+ }
+ if (!t)
+ {
+ t = build_variant_type_copy (type);
+ TREE_TYPE (t) = element_type;
+ }
+ return t;
+ }
/* A restrict-qualified pointer type must be a pointer to object or
incomplete type. Note that the use of POINTER_TYPE_P also allows
&& (!POINTER_TYPE_P (type)
|| !C_TYPE_OBJECT_OR_INCOMPLETE_P (TREE_TYPE (type))))
{
- error ("invalid use of `restrict'");
+ error ("invalid use of %<restrict%>");
type_quals &= ~TYPE_QUAL_RESTRICT;
}
c_apply_type_quals_to_decl (int type_quals, tree decl)
{
tree type = TREE_TYPE (decl);
-
+
if (type == error_mark_node)
return;
if (!type
|| !POINTER_TYPE_P (type)
|| !C_TYPE_OBJECT_OR_INCOMPLETE_P (TREE_TYPE (type)))
- error ("invalid use of `restrict'");
+ error ("invalid use of %<restrict%>");
else if (flag_strict_aliasing && type == TREE_TYPE (decl))
/* Indicate we need to make a unique alias set for this pointer.
We can't do it here because it might be pointing to an
{
int i = 0;
int shift, size;
- tree t = (tree)p;
+ tree t = (tree) p;
tree t2;
switch (TREE_CODE (t))
{
- /* For pointers, hash on pointee type plus some swizzling. */
+ /* For pointers, hash on pointee type plus some swizzling. */
case POINTER_TYPE:
return c_type_hash (TREE_TYPE (t)) ^ 0x3003003;
/* Hash on number of elements and total size. */
t2 = TYPE_FIELDS (t);
break;
default:
- abort ();
+ gcc_unreachable ();
}
for (; t2; t2 = TREE_CHAIN (t2))
i++;
return ((size << 24) | (i << shift));
}
+static GTY((param_is (union tree_node))) htab_t type_hash_table;
+
/* Return the typed-based alias set for T, which may be an expression
or a type. Return -1 if we don't do anything special. */
{
tree u;
PTR *slot;
- static htab_t type_hash_table;
/* Permit type-punning when accessing a union, provided the access
is directly through the union. For example, this code does not
return 0;
/* That's all the expressions we handle specially. */
- if (! TYPE_P (t))
+ if (!TYPE_P (t))
return -1;
/* The C standard guarantees that any object may be accessed via an
return -1;
/* Save time if there's only one input file. */
- if (!current_file_decl || TREE_CHAIN (current_file_decl) == NULL_TREE)
+ if (num_in_fnames == 1)
return -1;
/* Pointers need special handling if they point to any type that
{
tree t2;
/* Find bottom type under any nested POINTERs. */
- for (t2 = TREE_TYPE (t);
+ for (t2 = TREE_TYPE (t);
TREE_CODE (t2) == POINTER_TYPE;
t2 = TREE_TYPE (t2))
;
- if (TREE_CODE (t2) != RECORD_TYPE
+ if (TREE_CODE (t2) != RECORD_TYPE
&& TREE_CODE (t2) != ENUMERAL_TYPE
&& TREE_CODE (t2) != QUAL_UNION_TYPE
&& TREE_CODE (t2) != UNION_TYPE)
return -1;
}
/* These are the only cases that need special handling. */
- if (TREE_CODE (t) != RECORD_TYPE
+ if (TREE_CODE (t) != RECORD_TYPE
&& TREE_CODE (t) != ENUMERAL_TYPE
&& TREE_CODE (t) != QUAL_UNION_TYPE
&& TREE_CODE (t) != UNION_TYPE
if (TYPE_SIZE (t) == 0)
return -1;
- /* Look up t in hash table. Only one of the compatible types within each
+ /* Look up t in hash table. Only one of the compatible types within each
alias set is recorded in the table. */
if (!type_hash_table)
- type_hash_table = htab_create (1021, c_type_hash,
+ type_hash_table = htab_create_ggc (1021, c_type_hash,
(htab_eq) lang_hooks.types_compatible_p,
NULL);
slot = htab_find_slot (type_hash_table, t, INSERT);
if (*slot != NULL)
- return TYPE_ALIAS_SET ((tree)*slot);
+ {
+ TYPE_ALIAS_SET (t) = TYPE_ALIAS_SET ((tree)*slot);
+ return TYPE_ALIAS_SET ((tree)*slot);
+ }
else
/* Our caller will assign and record (in t) a new alias set; all we need
to do is remember t in the hash table. */
tree value = NULL;
enum tree_code type_code = TREE_CODE (type);
- my_friendly_assert (op == SIZEOF_EXPR || op == ALIGNOF_EXPR, 20020720);
+ gcc_assert (op == SIZEOF_EXPR || op == ALIGNOF_EXPR);
op_name = op == SIZEOF_EXPR ? "sizeof" : "__alignof__";
if (type_code == FUNCTION_TYPE)
if (op == SIZEOF_EXPR)
{
if (complain && (pedantic || warn_pointer_arith))
- pedwarn ("invalid application of `sizeof' to a function type");
+ pedwarn ("invalid application of %<sizeof%> to a function type");
value = size_one_node;
}
else
{
if (type_code == VOID_TYPE
&& complain && (pedantic || warn_pointer_arith))
- pedwarn ("invalid application of `%s' to a void type", op_name);
+ pedwarn ("invalid application of %qs to a void type", op_name);
value = size_one_node;
}
else if (!COMPLETE_TYPE_P (type))
{
if (complain)
- error ("invalid application of `%s' to incomplete type `%T' ",
+ error ("invalid application of %qs to incomplete type %qT ",
op_name, type);
value = size_zero_node;
}
else
{
- if (op == SIZEOF_EXPR)
+ if (op == (enum tree_code) 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);
+ value = size_int (TYPE_ALIGN_UNIT (type));
}
/* VALUE will have an integer type with TYPE_IS_SIZETYPE set.
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);
+ gcc_assert (!TYPE_IS_SIZETYPE (TREE_TYPE (value)));
return value;
}
tree t;
if (TREE_CODE (expr) == VAR_DECL)
- t = size_int (DECL_ALIGN (expr) / BITS_PER_UNIT);
+ t = size_int (DECL_ALIGN_UNIT (expr));
else if (TREE_CODE (expr) == COMPONENT_REF
&& DECL_C_BIT_FIELD (TREE_OPERAND (expr, 1)))
{
- error ("`__alignof' applied to a bit-field");
+ error ("%<__alignof%> applied to a bit-field");
t = size_one_node;
}
else if (TREE_CODE (expr) == COMPONENT_REF
&& TREE_CODE (TREE_OPERAND (expr, 1)) == FIELD_DECL)
- t = size_int (DECL_ALIGN (TREE_OPERAND (expr, 1)) / BITS_PER_UNIT);
+ t = size_int (DECL_ALIGN_UNIT (TREE_OPERAND (expr, 1)));
else if (TREE_CODE (expr) == INDIRECT_REF)
{
lang_hooks.decls.pushdecl (build_decl (TYPE_DECL, NULL_TREE,
intDI_type_node));
#if HOST_BITS_PER_WIDE_INT >= 64
- lang_hooks.decls.pushdecl (build_decl (TYPE_DECL,
- get_identifier ("__int128_t"),
- intTI_type_node));
+ if (targetm.scalar_mode_supported_p (TImode))
+ lang_hooks.decls.pushdecl (build_decl (TYPE_DECL,
+ get_identifier ("__int128_t"),
+ intTI_type_node));
#endif
lang_hooks.decls.pushdecl (build_decl (TYPE_DECL, NULL_TREE,
unsigned_intQI_type_node));
lang_hooks.decls.pushdecl (build_decl (TYPE_DECL, NULL_TREE,
unsigned_intDI_type_node));
#if HOST_BITS_PER_WIDE_INT >= 64
- lang_hooks.decls.pushdecl (build_decl (TYPE_DECL,
- get_identifier ("__uint128_t"),
- unsigned_intTI_type_node));
+ if (targetm.scalar_mode_supported_p (TImode))
+ lang_hooks.decls.pushdecl (build_decl (TYPE_DECL,
+ get_identifier ("__uint128_t"),
+ unsigned_intTI_type_node));
#endif
/* Create the widest literal types. */
if (c_dialect_cxx ())
/* For C++, make fileptr_type_node a distinct void * type until
FILE type is defined. */
- fileptr_type_node = build_type_copy (ptr_type_node);
+ fileptr_type_node = build_variant_type_copy (ptr_type_node);
record_builtin_type (RID_VOID, NULL, void_type_node);
- void_zero_node = build_int_2 (0, 0);
+ /* This node must not be shared. */
+ void_zero_node = make_node (INTEGER_CST);
TREE_TYPE (void_zero_node) = void_type_node;
void_list_node = build_void_list_node ();
(build_decl (TYPE_DECL, get_identifier ("__builtin_va_list"),
va_list_type_node));
- lang_hooks.decls.pushdecl
- (build_decl (TYPE_DECL, get_identifier ("__builtin_ptrdiff_t"),
- ptrdiff_type_node));
-
- lang_hooks.decls.pushdecl
- (build_decl (TYPE_DECL, get_identifier ("__builtin_size_t"),
- sizetype));
-
if (TREE_CODE (va_list_type_node) == ARRAY_TYPE)
{
va_list_arg_type_node = va_list_ref_type_node =
c_init_attributes ();
-#define DEF_BUILTIN(ENUM, NAME, CLASS, TYPE, LIBTYPE, \
- BOTH_P, FALLBACK_P, NONANSI_P, ATTRS, IMPLICIT) \
- if (NAME) \
+#define DEF_BUILTIN(ENUM, NAME, CLASS, TYPE, LIBTYPE, BOTH_P, FALLBACK_P, \
+ NONANSI_P, ATTRS, IMPLICIT, COND) \
+ if (NAME && COND) \
{ \
tree decl; \
\
- if (strncmp (NAME, "__builtin_", strlen ("__builtin_")) != 0) \
- abort (); \
+ gcc_assert (!strncmp (NAME, "__builtin_", \
+ strlen ("__builtin_"))); \
\
if (!BOTH_P) \
- decl = builtin_function (NAME, builtin_types[TYPE], ENUM, \
+ decl = lang_hooks.builtin_function (NAME, builtin_types[TYPE], \
+ ENUM, \
CLASS, \
(FALLBACK_P \
? (NAME + strlen ("__builtin_")) \
#include "builtins.def"
#undef DEF_BUILTIN
+ build_common_builtin_nodes ();
+
targetm.init_builtins ();
+ if (flag_mudflap)
+ mudflap_init ();
main_identifier_node = get_identifier ("main");
}
+/* Look up the function in built_in_decls that corresponds to DECL
+ and set ASMSPEC as its user assembler name. DECL must be a
+ function decl that declares a builtin. */
+
+void
+set_builtin_user_assembler_name (tree decl, const char *asmspec)
+{
+ tree builtin;
+ gcc_assert (TREE_CODE (decl) == FUNCTION_DECL
+ && DECL_BUILT_IN_CLASS (decl) == BUILT_IN_NORMAL
+ && asmspec != 0);
+
+ builtin = built_in_decls [DECL_FUNCTION_CODE (decl)];
+ set_user_assembler_name (builtin, asmspec);
+ if (DECL_FUNCTION_CODE (decl) == BUILT_IN_MEMCPY)
+ init_block_move_fn (asmspec);
+ else if (DECL_FUNCTION_CODE (decl) == BUILT_IN_MEMSET)
+ init_block_clear_fn (asmspec);
+}
+
tree
build_va_arg (tree expr, tree type)
{
disable_builtin_function (const char *name)
{
if (strncmp (name, "__builtin_", strlen ("__builtin_")) == 0)
- error ("cannot disable built-in function `%s'", name);
+ error ("cannot disable built-in function %qs", name);
else
{
- disabled_builtin *new = xmalloc (sizeof (disabled_builtin));
- new->name = name;
- new->next = disabled_builtins;
- disabled_builtins = new;
+ disabled_builtin *new_disabled_builtin = XNEW (disabled_builtin);
+ new_disabled_builtin->name = name;
+ new_disabled_builtin->next = disabled_builtins;
+ disabled_builtins = new_disabled_builtin;
}
}
BUILTIN_TYPE is the type of the __builtin_-prefixed function;
TYPE is the type of the function with the ordinary name. These
may differ if the ordinary name is declared with a looser type to avoid
- conflicts with headers. FUNCTION_CODE and CLASS are as for
+ conflicts with headers. FUNCTION_CODE and CL 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 NONANSI_P is true, 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,
static tree
builtin_function_2 (const char *builtin_name, const char *name,
- tree builtin_type, tree type, int function_code,
- enum built_in_class class, int library_name_p,
- int nonansi_p, tree attrs)
+ tree builtin_type, tree type,
+ enum built_in_function function_code,
+ enum built_in_class cl, int library_name_p,
+ bool nonansi_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, attrs);
+ bdecl = lang_hooks.builtin_function (builtin_name, builtin_type,
+ function_code, cl,
+ 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, attrs);
+ decl = lang_hooks.builtin_function (name, type, function_code, cl,
+ NULL, attrs);
return (bdecl != 0 ? bdecl : decl);
}
return t;
}
-static tree expand_unordered_cmp (tree, tree, enum tree_code, enum tree_code);
-
-/* Expand a call to an unordered comparison function such as
- __builtin_isgreater(). FUNCTION is the function's declaration and
- PARAMS a list of the values passed. For __builtin_isunordered(),
- UNORDERED_CODE is UNORDERED_EXPR and ORDERED_CODE is NOP_EXPR. In
- other cases, UNORDERED_CODE and ORDERED_CODE are comparison codes
- that give the opposite of the desired result. UNORDERED_CODE is
- used for modes that can hold NaNs and ORDERED_CODE is used for the
- rest. */
+/* Used to compare case labels. K1 and K2 are actually tree nodes
+ representing case labels, or NULL_TREE for a `default' label.
+ Returns -1 if K1 is ordered before K2, -1 if K1 is ordered after
+ K2, and 0 if K1 and K2 are equal. */
-static tree
-expand_unordered_cmp (tree function, tree params,
- enum tree_code unordered_code,
- enum tree_code ordered_code)
+int
+case_compare (splay_tree_key k1, splay_tree_key k2)
{
- tree arg0, arg1, type;
- enum tree_code code0, code1;
+ /* Consider a NULL key (such as arises with a `default' label) to be
+ smaller than anything else. */
+ if (!k1)
+ return k2 ? -1 : 0;
+ else if (!k2)
+ return k1 ? 1 : 0;
- /* 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;
- }
+ return tree_int_cst_compare ((tree) k1, (tree) k2);
+}
- arg0 = TREE_VALUE (params);
- arg1 = TREE_VALUE (TREE_CHAIN (params));
+/* Process a case label for the range LOW_VALUE ... HIGH_VALUE. If
+ LOW_VALUE and HIGH_VALUE are both NULL_TREE then this case label is
+ actually a `default' label. If only HIGH_VALUE is NULL_TREE, then
+ case label was declared using the usual C/C++ syntax, rather than
+ the GNU case range extension. CASES is a tree containing all the
+ case ranges processed so far; COND is the condition for the
+ switch-statement itself. Returns the CASE_LABEL_EXPR created, or
+ ERROR_MARK_NODE if no CASE_LABEL_EXPR is created. */
- code0 = TREE_CODE (TREE_TYPE (arg0));
- code1 = TREE_CODE (TREE_TYPE (arg1));
+tree
+c_add_case_label (splay_tree cases, tree cond, tree orig_type,
+ tree low_value, tree high_value)
+{
+ tree type;
+ tree label;
+ tree case_label;
+ splay_tree_node node;
- /* 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));
+ /* Create the LABEL_DECL itself. */
+ label = create_artificial_label ();
- 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 there was an error processing the switch condition, bail now
+ before we get more confused. */
+ if (!cond || cond == error_mark_node)
+ goto error_out;
- if (unordered_code == UNORDERED_EXPR)
+ if ((low_value && TREE_TYPE (low_value)
+ && POINTER_TYPE_P (TREE_TYPE (low_value)))
+ || (high_value && TREE_TYPE (high_value)
+ && POINTER_TYPE_P (TREE_TYPE (high_value))))
{
- 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;
+ error ("pointers are not permitted as case values");
+ goto error_out;
}
- return build_unary_op (TRUTH_NOT_EXPR,
- build_binary_op (MODE_HAS_NANS (TYPE_MODE (type))
- ? unordered_code
- : ordered_code,
- convert (type, arg0),
- convert (type, arg1),
- 0),
- 0);
-}
-
-
-/* Recognize certain built-in functions so we can make tree-codes
- other than CALL_EXPR. We do this when it enables fold-const.c
- to do something useful. */
-/* ??? By rights this should go in builtins.c, but only C and C++
- implement build_{binary,unary}_op. Not exactly sure what bits
- of functionality are actually needed from those functions, or
- where the similar functionality exists in the other front ends. */
-
-tree
-expand_tree_builtin (tree function, tree params, tree coerced_params)
-{
- if (DECL_BUILT_IN_CLASS (function) != BUILT_IN_NORMAL)
- return NULL_TREE;
-
- switch (DECL_FUNCTION_CODE (function))
- {
- case BUILT_IN_ABS:
- case BUILT_IN_LABS:
- case BUILT_IN_LLABS:
- case BUILT_IN_IMAXABS:
- case BUILT_IN_FABS:
- case BUILT_IN_FABSL:
- case BUILT_IN_FABSF:
- if (coerced_params == 0)
- return integer_zero_node;
- return build_unary_op (ABS_EXPR, TREE_VALUE (coerced_params), 0);
-
- case BUILT_IN_CONJ:
- case BUILT_IN_CONJF:
- case BUILT_IN_CONJL:
- if (coerced_params == 0)
- return integer_zero_node;
- return build_unary_op (CONJ_EXPR, TREE_VALUE (coerced_params), 0);
-
- case BUILT_IN_CREAL:
- case BUILT_IN_CREALF:
- case BUILT_IN_CREALL:
- if (coerced_params == 0)
- return integer_zero_node;
- return non_lvalue (build_unary_op (REALPART_EXPR,
- TREE_VALUE (coerced_params), 0));
-
- case BUILT_IN_CIMAG:
- case BUILT_IN_CIMAGF:
- case BUILT_IN_CIMAGL:
- if (coerced_params == 0)
- return integer_zero_node;
- return non_lvalue (build_unary_op (IMAGPART_EXPR,
- TREE_VALUE (coerced_params), 0));
-
- case BUILT_IN_ISGREATER:
- return expand_unordered_cmp (function, params, UNLE_EXPR, LE_EXPR);
-
- case BUILT_IN_ISGREATEREQUAL:
- return expand_unordered_cmp (function, params, UNLT_EXPR, LT_EXPR);
-
- case BUILT_IN_ISLESS:
- return expand_unordered_cmp (function, params, UNGE_EXPR, GE_EXPR);
-
- case BUILT_IN_ISLESSEQUAL:
- return expand_unordered_cmp (function, params, UNGT_EXPR, GT_EXPR);
-
- case BUILT_IN_ISLESSGREATER:
- return expand_unordered_cmp (function, params, UNEQ_EXPR, EQ_EXPR);
-
- case BUILT_IN_ISUNORDERED:
- return expand_unordered_cmp (function, params, UNORDERED_EXPR, NOP_EXPR);
-
- default:
- break;
- }
-
- return NULL_TREE;
-}
-
-/* Walk the statement tree, rooted at *tp. Apply FUNC to all the
- sub-trees of *TP in a pre-order traversal. FUNC is called with the
- DATA and the address of each sub-tree. If FUNC returns a non-NULL
- value, the traversal is aborted, and the value returned by FUNC is
- returned. If FUNC sets WALK_SUBTREES to zero, then the subtrees of
- the node being visited are not walked.
-
- We don't need a without_duplicates variant of this one because the
- statement tree is a tree, not a graph. */
-
-tree
-walk_stmt_tree (tree *tp, walk_tree_fn func, void *data)
-{
- enum tree_code code;
- int walk_subtrees;
- tree result;
- int i, len;
-
-#define WALK_SUBTREE(NODE) \
- do \
- { \
- result = walk_stmt_tree (&(NODE), func, data); \
- if (result) \
- return result; \
- } \
- while (0)
-
- /* Skip empty subtrees. */
- if (!*tp)
- return NULL_TREE;
-
- /* Skip subtrees below non-statement nodes. */
- if (!STATEMENT_CODE_P (TREE_CODE (*tp)))
- return NULL_TREE;
-
- /* Call the function. */
- walk_subtrees = 1;
- result = (*func) (tp, &walk_subtrees, data);
-
- /* If we found something, return it. */
- if (result)
- return result;
-
- /* FUNC may have modified the tree, recheck that we're looking at a
- statement node. */
- code = TREE_CODE (*tp);
- if (!STATEMENT_CODE_P (code))
- return NULL_TREE;
-
- /* Visit the subtrees unless FUNC decided that there was nothing
- interesting below this point in the tree. */
- if (walk_subtrees)
- {
- /* Walk over all the sub-trees of this operand. Statement nodes
- never contain RTL, and we needn't worry about TARGET_EXPRs. */
- len = TREE_CODE_LENGTH (code);
-
- /* Go through the subtrees. We need to do this in forward order so
- that the scope of a FOR_EXPR is handled properly. */
- for (i = 0; i < len; ++i)
- WALK_SUBTREE (TREE_OPERAND (*tp, i));
- }
-
- /* Finally visit the chain. This can be tail-recursion optimized if
- we write it this way. */
- return walk_stmt_tree (&TREE_CHAIN (*tp), func, data);
-
-#undef WALK_SUBTREE
-}
-
-/* Used to compare case labels. K1 and K2 are actually tree nodes
- representing case labels, or NULL_TREE for a `default' label.
- Returns -1 if K1 is ordered before K2, -1 if K1 is ordered after
- K2, and 0 if K1 and K2 are equal. */
-
-int
-case_compare (splay_tree_key k1, splay_tree_key k2)
-{
- /* Consider a NULL key (such as arises with a `default' label) to be
- smaller than anything else. */
- if (!k1)
- return k2 ? -1 : 0;
- else if (!k2)
- return k1 ? 1 : 0;
-
- return tree_int_cst_compare ((tree) k1, (tree) k2);
-}
-
-/* Process a case label for the range LOW_VALUE ... HIGH_VALUE. If
- LOW_VALUE and HIGH_VALUE are both NULL_TREE then this case label is
- actually a `default' label. If only HIGH_VALUE is NULL_TREE, then
- case label was declared using the usual C/C++ syntax, rather than
- the GNU case range extension. CASES is a tree containing all the
- case ranges processed so far; COND is the condition for the
- switch-statement itself. Returns the CASE_LABEL_EXPR created, or
- ERROR_MARK_NODE if no CASE_LABEL_EXPR is created. */
-
-tree
-c_add_case_label (splay_tree cases, tree cond, tree low_value,
- tree high_value)
-{
- tree type;
- tree label;
- tree case_label;
- splay_tree_node node;
-
- /* Create the LABEL_DECL itself. */
- label = create_artificial_label ();
-
- /* If there was an error processing the switch condition, bail now
- before we get more confused. */
- if (!cond || cond == error_mark_node)
- goto error_out;
-
- if ((low_value && TREE_TYPE (low_value)
- && POINTER_TYPE_P (TREE_TYPE (low_value)))
- || (high_value && TREE_TYPE (high_value)
- && POINTER_TYPE_P (TREE_TYPE (high_value))))
- error ("pointers are not permitted as case values");
-
- /* Case ranges are a GNU extension. */
- if (high_value && pedantic)
- pedwarn ("range expressions in switch statements are non-standard");
+ /* Case ranges are a GNU extension. */
+ if (high_value && pedantic)
+ pedwarn ("range expressions in switch statements are non-standard");
type = TREE_TYPE (cond);
if (low_value)
&& !tree_int_cst_lt (low_value, high_value))
warning ("empty range specified");
+ /* See if the case is in range of the type of the original testing
+ expression. If both low_value and high_value are out of range,
+ don't insert the case label and return NULL_TREE. */
+ if (low_value
+ && !check_case_bounds (type, orig_type,
+ &low_value, high_value ? &high_value : NULL))
+ return NULL_TREE;
+
/* Look up the LOW_VALUE in the table of case labels we already
have. */
node = splay_tree_lookup (cases, (splay_tree_key) low_value);
TREE_INT_CST_HIGH (key), TREE_INT_CST_LOW (key));
if (TYPE_NAME (type) == 0)
- warning ("%Jcase value `%s' not in enumerated type",
+ warning ("%Jcase value %qs not in enumerated type",
CASE_LABEL (label), buf);
else
- warning ("%Jcase value `%s' not in enumerated type `%T'",
+ warning ("%Jcase value %qs not in enumerated type %qT",
CASE_LABEL (label), buf, type);
}
match_case_to_enum (splay_tree_node node, void *data)
{
tree label = (tree) node->value;
- tree type = data;
+ tree type = (tree) data;
/* Skip default case. */
if (!CASE_LOW (label))
/* Handle -Wswitch*. Called from the front end after parsing the switch
construct. */
/* ??? Should probably be somewhere generic, since other languages besides
- C and C++ would want this. We'd want to agree on the datastructure,
+ C and C++ would want this. We'd want to agree on the data structure,
however, which is a problem. Alternately, we operate on gimplified
switch_exprs, which I don't especially like. At the moment, however,
C/C++ are the only tree-ssa languages that support enumerations at all,
void
c_do_switch_warnings (splay_tree cases, tree switch_stmt)
{
- splay_tree_node default_node;
- location_t *switch_locus;
+ splay_tree_node default_node;
+ location_t switch_location;
tree type;
if (!warn_switch && !warn_switch_enum && !warn_switch_default)
return;
- switch_locus = EXPR_LOCUS (switch_stmt);
- if (!switch_locus)
- switch_locus = &input_location;
- type = SWITCH_TYPE (switch_stmt);
+ if (EXPR_HAS_LOCATION (switch_stmt))
+ switch_location = EXPR_LOCATION (switch_stmt);
+ else
+ switch_location = input_location;
+
+ type = SWITCH_STMT_TYPE (switch_stmt);
default_node = splay_tree_lookup (cases, (splay_tree_key) NULL);
if (warn_switch_default && !default_node)
- warning ("%Hswitch missing default case", switch_locus);
+ warning ("%Hswitch missing default case", &switch_location);
/* If the switch expression was an enumerated type, check that
exactly all enumeration literals are covered by the cases.
default case, or when -Wswitch-enum was specified. */
if (((warn_switch && !default_node) || warn_switch_enum)
&& type && TREE_CODE (type) == ENUMERAL_TYPE
- && TREE_CODE (SWITCH_COND (switch_stmt)) != INTEGER_CST)
+ && TREE_CODE (SWITCH_STMT_COND (switch_stmt)) != INTEGER_CST)
{
tree chain;
/* The time complexity here is O(N*lg(N)) worst case, but for the
- common case of monotonically increasing enumerators, it is
+ common case of monotonically increasing enumerators, it is
O(N), since the nature of the splay tree will keep the next
element adjacent to the root at all times. */
if (node)
{
/* Mark the CASE_LOW part of the case entry as seen, so
- that we save time later. Choose TREE_ADDRESSABLE
+ that we save time later. Choose TREE_ADDRESSABLE
randomly as a bit that won't have been set to-date. */
tree label = (tree) node->value;
TREE_ADDRESSABLE (label) = 1;
{
/* Warn if there are enumerators that don't correspond to
case expressions. */
- warning ("%Henumeration value `%E' not handled in switch",
- switch_locus, TREE_PURPOSE (chain));
+ warning ("%Henumeration value %qE not handled in switch",
+ &switch_location, TREE_PURPOSE (chain));
}
}
The time complexity here is O(N**2) worst case, since we've
not sorted the enumeration values. However, in the absence
- of case ranges this is O(N), since all single cases that
+ of case ranges this is O(N), since all single cases that
corresponded to enumerations have been marked above. */
splay_tree_foreach (cases, match_case_to_enum, type);
}
/* Hook used by expand_expr to expand language-specific tree codes. */
-/* The only things that should go here are bits needed to expand
+/* The only things that should go here are bits needed to expand
constant initializers. Everything else should be handled by the
gimplification routines. */
rtx
-c_expand_expr (tree exp, rtx target, enum machine_mode tmode,
+c_expand_expr (tree exp, rtx target, enum machine_mode tmode,
int modifier /* Actually enum_modifier. */,
rtx *alt_rtl)
{
}
default:
- abort ();
+ gcc_unreachable ();
}
}
-/* Hook used by safe_from_p to handle language-specific tree codes. */
-
-int
-c_safe_from_p (rtx target, tree exp)
-{
- /* We can see statements here when processing the body of a
- statement-expression. For a declaration statement declaring a
- variable, look at the variable's initializer. */
- if (TREE_CODE (exp) == DECL_STMT)
- {
- tree decl = DECL_STMT_DECL (exp);
-
- if (TREE_CODE (decl) == VAR_DECL
- && DECL_INITIAL (decl)
- && !safe_from_p (target, DECL_INITIAL (decl), /*top_p=*/0))
- return 0;
- }
-
- /* Assume everything else is safe. */
- return 1;
-}
-
-/* Hook used by unsafe_for_reeval to handle language-specific tree codes. */
-
-int
-c_common_unsafe_for_reeval (tree exp)
-{
- /* Statement expressions may not be reevaluated, likewise compound
- literals. */
- if (TREE_CODE (exp) == STMT_EXPR
- || TREE_CODE (exp) == COMPOUND_LITERAL_EXPR)
- return 2;
-
- /* Walk all other expressions. */
- return -1;
-}
-
/* Hook used by staticp to handle language-specific tree codes. */
-int
+tree
c_staticp (tree exp)
{
- if (TREE_CODE (exp) == COMPOUND_LITERAL_EXPR
- && TREE_STATIC (COMPOUND_LITERAL_EXPR_DECL (exp)))
- return 1;
- return 0;
+ return (TREE_CODE (exp) == COMPOUND_LITERAL_EXPR
+ && TREE_STATIC (COMPOUND_LITERAL_EXPR_DECL (exp))
+ ? exp : NULL);
}
\f
switch (code)
{
case PREINCREMENT_EXPR:
- val = build (MODIFY_EXPR, TREE_TYPE (arg), arg, true_res);
+ val = build2 (MODIFY_EXPR, TREE_TYPE (arg), arg, true_res);
break;
case POSTINCREMENT_EXPR:
- val = build (MODIFY_EXPR, TREE_TYPE (arg), arg, true_res);
+ val = build2 (MODIFY_EXPR, TREE_TYPE (arg), arg, true_res);
arg = save_expr (arg);
- val = build (COMPOUND_EXPR, TREE_TYPE (arg), val, arg);
- val = build (COMPOUND_EXPR, TREE_TYPE (arg), arg, val);
+ val = build2 (COMPOUND_EXPR, TREE_TYPE (arg), val, arg);
+ val = build2 (COMPOUND_EXPR, TREE_TYPE (arg), arg, val);
break;
case PREDECREMENT_EXPR:
- val = build (MODIFY_EXPR, TREE_TYPE (arg), arg, invert_truthvalue (arg));
+ val = build2 (MODIFY_EXPR, TREE_TYPE (arg), arg,
+ invert_truthvalue (arg));
break;
case POSTDECREMENT_EXPR:
- val = build (MODIFY_EXPR, TREE_TYPE (arg), arg, invert_truthvalue (arg));
+ val = build2 (MODIFY_EXPR, TREE_TYPE (arg), arg,
+ invert_truthvalue (arg));
arg = save_expr (arg);
- val = build (COMPOUND_EXPR, TREE_TYPE (arg), val, arg);
- val = build (COMPOUND_EXPR, TREE_TYPE (arg), arg, val);
+ val = build2 (COMPOUND_EXPR, TREE_TYPE (arg), val, arg);
+ val = build2 (COMPOUND_EXPR, TREE_TYPE (arg), arg, val);
break;
default:
- abort ();
+ gcc_unreachable ();
}
TREE_SIDE_EFFECTS (val) = 1;
return val;
builtin_define_with_value ("__PTRDIFF_TYPE__", PTRDIFF_TYPE, 0);
builtin_define_with_value ("__WCHAR_TYPE__", MODIFIED_WCHAR_TYPE, 0);
builtin_define_with_value ("__WINT_TYPE__", WINT_TYPE, 0);
+ builtin_define_with_value ("__INTMAX_TYPE__", INTMAX_TYPE, 0);
+ builtin_define_with_value ("__UINTMAX_TYPE__", UINTMAX_TYPE, 0);
}
static void
c_init_attributes (void)
{
/* Fill in the built_in_attributes array. */
-#define DEF_ATTR_NULL_TREE(ENUM) \
+#define DEF_ATTR_NULL_TREE(ENUM) \
built_in_attributes[(int) ENUM] = NULL_TREE;
-#define DEF_ATTR_INT(ENUM, VALUE) \
- built_in_attributes[(int) ENUM] = build_int_2 (VALUE, VALUE < 0 ? -1 : 0);
+#define DEF_ATTR_INT(ENUM, VALUE) \
+ built_in_attributes[(int) ENUM] = build_int_cst (NULL_TREE, VALUE);
#define DEF_ATTR_IDENT(ENUM, STRING) \
built_in_attributes[(int) ENUM] = get_identifier (STRING);
#define DEF_ATTR_TREE_LIST(ENUM, PURPOSE, VALUE, CHAIN) \
struct attribute_spec.handler. */
static tree
-handle_packed_attribute (tree *node, tree name, tree args ATTRIBUTE_UNUSED,
+handle_packed_attribute (tree *node, tree name, tree ARG_UNUSED (args),
int flags, bool *no_add_attrs)
{
if (TYPE_P (*node))
{
if (!(flags & (int) ATTR_FLAG_TYPE_IN_PLACE))
- *node = build_type_copy (*node);
+ *node = build_variant_type_copy (*node);
TYPE_PACKED (*node) = 1;
if (TYPE_MAIN_VARIANT (*node) == *node)
{
/* If it is the main variant, then pack the other variants
too. This happens in,
-
+
struct Foo {
struct Foo const *ptr; // creates a variant w/o packed flag
} __ attribute__((packed)); // packs it now.
*/
tree probe;
-
+
for (probe = *node; probe; probe = TYPE_NEXT_VARIANT (probe))
TYPE_PACKED (probe) = 1;
}
-
+
}
else if (TREE_CODE (*node) == FIELD_DECL)
DECL_PACKED (*node) = 1;
that changes what the typedef is typing. */
else
{
- warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
+ warning ("%qE attribute ignored", name);
*no_add_attrs = true;
}
static tree
handle_nocommon_attribute (tree *node, tree name,
- tree args ATTRIBUTE_UNUSED,
- int flags ATTRIBUTE_UNUSED, bool *no_add_attrs)
+ tree ARG_UNUSED (args),
+ int ARG_UNUSED (flags), bool *no_add_attrs)
{
if (TREE_CODE (*node) == VAR_DECL)
DECL_COMMON (*node) = 0;
else
{
- warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
+ warning ("%qE attribute ignored", name);
*no_add_attrs = true;
}
struct attribute_spec.handler. */
static tree
-handle_common_attribute (tree *node, tree name, tree args ATTRIBUTE_UNUSED,
- int flags ATTRIBUTE_UNUSED, bool *no_add_attrs)
+handle_common_attribute (tree *node, tree name, tree ARG_UNUSED (args),
+ int ARG_UNUSED (flags), bool *no_add_attrs)
{
if (TREE_CODE (*node) == VAR_DECL)
DECL_COMMON (*node) = 1;
else
{
- warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
+ warning ("%qE attribute ignored", name);
*no_add_attrs = true;
}
struct attribute_spec.handler. */
static tree
-handle_noreturn_attribute (tree *node, tree name, tree args ATTRIBUTE_UNUSED,
- int flags ATTRIBUTE_UNUSED, bool *no_add_attrs)
+handle_noreturn_attribute (tree *node, tree name, tree ARG_UNUSED (args),
+ int ARG_UNUSED (flags), bool *no_add_attrs)
{
tree type = TREE_TYPE (*node);
TYPE_READONLY (TREE_TYPE (type)), 1));
else
{
- warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
+ warning ("%qE attribute ignored", name);
*no_add_attrs = true;
}
static tree
handle_noinline_attribute (tree *node, tree name,
- tree args ATTRIBUTE_UNUSED,
- int flags ATTRIBUTE_UNUSED, bool *no_add_attrs)
+ tree ARG_UNUSED (args),
+ int ARG_UNUSED (flags), bool *no_add_attrs)
{
if (TREE_CODE (*node) == FUNCTION_DECL)
DECL_UNINLINABLE (*node) = 1;
else
{
- warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
+ warning ("%qE attribute ignored", name);
*no_add_attrs = true;
}
static tree
handle_always_inline_attribute (tree *node, tree name,
- tree args ATTRIBUTE_UNUSED,
- int flags ATTRIBUTE_UNUSED,
+ tree ARG_UNUSED (args),
+ int ARG_UNUSED (flags),
bool *no_add_attrs)
{
if (TREE_CODE (*node) == FUNCTION_DECL)
}
else
{
- warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
+ warning ("%qE attribute ignored", name);
*no_add_attrs = true;
}
struct attribute_spec.handler. */
static tree
-handle_used_attribute (tree *pnode, tree name, tree args ATTRIBUTE_UNUSED,
- int flags ATTRIBUTE_UNUSED, bool *no_add_attrs)
+handle_used_attribute (tree *pnode, tree name, tree ARG_UNUSED (args),
+ int ARG_UNUSED (flags), bool *no_add_attrs)
{
tree node = *pnode;
|| (TREE_CODE (node) == VAR_DECL && TREE_STATIC (node)))
{
TREE_USED (node) = 1;
+ DECL_PRESERVE_P (node) = 1;
}
else
{
- warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
+ warning ("%qE attribute ignored", name);
*no_add_attrs = true;
}
struct attribute_spec.handler. */
static tree
-handle_unused_attribute (tree *node, tree name, tree args ATTRIBUTE_UNUSED,
- int flags ATTRIBUTE_UNUSED, bool *no_add_attrs)
+handle_unused_attribute (tree *node, tree name, tree ARG_UNUSED (args),
+ int flags, bool *no_add_attrs)
{
if (DECL_P (*node))
{
TREE_USED (decl) = 1;
else
{
- warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
+ warning ("%qE attribute ignored", name);
*no_add_attrs = true;
}
}
else
{
if (!(flags & (int) ATTR_FLAG_TYPE_IN_PLACE))
- *node = build_type_copy (*node);
+ *node = build_variant_type_copy (*node);
TREE_USED (*node) = 1;
}
struct attribute_spec.handler. */
static tree
-handle_const_attribute (tree *node, tree name, tree args ATTRIBUTE_UNUSED,
- int flags ATTRIBUTE_UNUSED, bool *no_add_attrs)
+handle_const_attribute (tree *node, tree name, tree ARG_UNUSED (args),
+ int ARG_UNUSED (flags), bool *no_add_attrs)
{
tree type = TREE_TYPE (*node);
TREE_THIS_VOLATILE (TREE_TYPE (type))));
else
{
- warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
+ warning ("%qE attribute ignored", name);
*no_add_attrs = true;
}
static tree
handle_transparent_union_attribute (tree *node, tree name,
- tree args ATTRIBUTE_UNUSED, int flags,
+ tree ARG_UNUSED (args), int flags,
bool *no_add_attrs)
{
tree decl = NULL_TREE;
&& TYPE_MODE (*type) == DECL_MODE (TYPE_FIELDS (*type)))))
{
if (!(flags & (int) ATTR_FLAG_TYPE_IN_PLACE))
- *type = build_type_copy (*type);
+ *type = build_variant_type_copy (*type);
TYPE_TRANSPARENT_UNION (*type) = 1;
}
else if (decl != 0 && TREE_CODE (decl) == PARM_DECL
DECL_TRANSPARENT_UNION (decl) = 1;
else
{
- warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
+ warning ("%qE attribute ignored", name);
*no_add_attrs = true;
}
static tree
handle_constructor_attribute (tree *node, tree name,
- tree args ATTRIBUTE_UNUSED,
- int flags ATTRIBUTE_UNUSED,
+ tree ARG_UNUSED (args),
+ int ARG_UNUSED (flags),
bool *no_add_attrs)
{
tree decl = *node;
}
else
{
- warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
+ warning ("%qE attribute ignored", name);
*no_add_attrs = true;
}
static tree
handle_destructor_attribute (tree *node, tree name,
- tree args ATTRIBUTE_UNUSED,
- int flags ATTRIBUTE_UNUSED,
+ tree ARG_UNUSED (args),
+ int ARG_UNUSED (flags),
bool *no_add_attrs)
{
tree decl = *node;
}
else
{
- warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
+ warning ("%qE attribute ignored", name);
*no_add_attrs = true;
}
struct attribute_spec.handler. */
static tree
-handle_mode_attribute (tree *node, tree name, tree args ATTRIBUTE_UNUSED,
- int flags ATTRIBUTE_UNUSED, bool *no_add_attrs)
+handle_mode_attribute (tree *node, tree name, tree args,
+ int ARG_UNUSED (flags), bool *no_add_attrs)
{
tree type = *node;
*no_add_attrs = true;
if (TREE_CODE (TREE_VALUE (args)) != IDENTIFIER_NODE)
- warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
+ warning ("%qE attribute ignored", name);
else
{
int j;
int len = strlen (p);
enum machine_mode mode = VOIDmode;
tree typefm;
- tree ptr_type;
+ bool valid_mode;
if (len > 4 && p[0] == '_' && p[1] == '_'
&& p[len - 1] == '_' && p[len - 2] == '_')
{
- char *newp = alloca (len - 1);
+ char *newp = (char *) alloca (len - 1);
strcpy (newp, &p[2]);
newp[len - 4] = '\0';
/* Change this type to have a type with the specified mode.
First check for the special modes. */
- if (! strcmp (p, "byte"))
+ if (!strcmp (p, "byte"))
mode = byte_mode;
else if (!strcmp (p, "word"))
mode = word_mode;
- else if (! strcmp (p, "pointer"))
+ else if (!strcmp (p, "pointer"))
mode = ptr_mode;
else
for (j = 0; j < NUM_MACHINE_MODES; j++)
if (!strcmp (p, GET_MODE_NAME (j)))
- mode = (enum machine_mode) j;
+ {
+ mode = (enum machine_mode) j;
+ break;
+ }
if (mode == VOIDmode)
{
- error ("unknown machine mode `%s'", p);
+ error ("unknown machine mode %qs", p);
return NULL_TREE;
}
- if (VECTOR_MODE_P (mode))
+ valid_mode = false;
+ switch (GET_MODE_CLASS (mode))
{
+ case MODE_INT:
+ case MODE_PARTIAL_INT:
+ case MODE_FLOAT:
+ valid_mode = targetm.scalar_mode_supported_p (mode);
+ break;
+
+ case MODE_COMPLEX_INT:
+ case MODE_COMPLEX_FLOAT:
+ valid_mode = targetm.scalar_mode_supported_p (GET_MODE_INNER (mode));
+ break;
+
+ case MODE_VECTOR_INT:
+ case MODE_VECTOR_FLOAT:
warning ("specifying vector types with __attribute__ ((mode)) "
"is deprecated");
warning ("use __attribute__ ((vector_size)) instead");
- }
+ valid_mode = vector_mode_valid_p (mode);
+ break;
- typefm = lang_hooks.types.type_for_mode (mode, TYPE_UNSIGNED (type));
- if (typefm == NULL_TREE)
- error ("no data type for mode `%s'", p);
+ default:
+ break;
+ }
+ if (!valid_mode)
+ {
+ error ("unable to emulate %qs", p);
+ return NULL_TREE;
+ }
- else if ((TREE_CODE (type) == POINTER_TYPE
- || TREE_CODE (type) == REFERENCE_TYPE)
- && !targetm.valid_pointer_mode (mode))
- error ("invalid pointer mode `%s'", p);
- else
+ if (POINTER_TYPE_P (type))
{
- /* If this is a vector, make sure we either have hardware
- support, or we can emulate it. */
- if (VECTOR_MODE_P (mode) && !vector_mode_valid_p (mode))
+ tree (*fn)(tree, enum machine_mode, bool);
+
+ if (!targetm.valid_pointer_mode (mode))
{
- error ("unable to emulate '%s'", GET_MODE_NAME (mode));
+ error ("invalid pointer mode %qs", p);
return NULL_TREE;
}
- if (TREE_CODE (type) == POINTER_TYPE)
- {
- ptr_type = build_pointer_type_for_mode (TREE_TYPE (type),
- mode, false);
- *node = ptr_type;
- }
- else if (TREE_CODE (type) == REFERENCE_TYPE)
+ if (TREE_CODE (type) == POINTER_TYPE)
+ fn = build_pointer_type_for_mode;
+ else
+ fn = build_reference_type_for_mode;
+ typefm = fn (TREE_TYPE (type), mode, false);
+ }
+ else
+ typefm = lang_hooks.types.type_for_mode (mode, TYPE_UNSIGNED (type));
+
+ if (typefm == NULL_TREE)
+ {
+ error ("no data type for mode %qs", p);
+ return NULL_TREE;
+ }
+ else if (TREE_CODE (type) == ENUMERAL_TYPE)
+ {
+ /* For enumeral types, copy the precision from the integer
+ type returned above. If not an INTEGER_TYPE, we can't use
+ this mode for this type. */
+ if (TREE_CODE (typefm) != INTEGER_TYPE)
{
- ptr_type = build_reference_type_for_mode (TREE_TYPE (type),
- mode, false);
- *node = ptr_type;
+ error ("cannot use mode %qs for enumeral types", p);
+ return NULL_TREE;
}
- else
- *node = typefm;
- /* No need to layout the type here. The caller should do this. */
+
+ if (!(flags & (int) ATTR_FLAG_TYPE_IN_PLACE))
+ type = build_variant_type_copy (type);
+
+ /* We cannot use layout_type here, because that will attempt
+ to re-layout all variants, corrupting our original. */
+ TYPE_PRECISION (type) = TYPE_PRECISION (typefm);
+ TYPE_MIN_VALUE (type) = TYPE_MIN_VALUE (typefm);
+ TYPE_MAX_VALUE (type) = TYPE_MAX_VALUE (typefm);
+ TYPE_SIZE (type) = TYPE_SIZE (typefm);
+ TYPE_SIZE_UNIT (type) = TYPE_SIZE_UNIT (typefm);
+ TYPE_MODE (type) = TYPE_MODE (typefm);
+ if (!TYPE_USER_ALIGN (type))
+ TYPE_ALIGN (type) = TYPE_ALIGN (typefm);
+
+ typefm = type;
+ }
+ else if (VECTOR_MODE_P (mode)
+ ? TREE_CODE (type) != TREE_CODE (TREE_TYPE (typefm))
+ : TREE_CODE (type) != TREE_CODE (typefm))
+ {
+ error ("mode %qs applied to inappropriate type", p);
+ return NULL_TREE;
}
+
+ *node = typefm;
}
return NULL_TREE;
struct attribute_spec.handler. */
static tree
-handle_section_attribute (tree *node, tree name ATTRIBUTE_UNUSED, tree args,
- int flags ATTRIBUTE_UNUSED, bool *no_add_attrs)
+handle_section_attribute (tree *node, tree ARG_UNUSED (name), tree args,
+ int ARG_UNUSED (flags), bool *no_add_attrs)
{
tree decl = *node;
if (targetm.have_named_sections)
{
+ user_defined_section_attribute = true;
+
if ((TREE_CODE (decl) == FUNCTION_DECL
|| TREE_CODE (decl) == VAR_DECL)
&& TREE_CODE (TREE_VALUE (args)) == STRING_CST)
{
if (TREE_CODE (decl) == VAR_DECL
&& current_function_decl != NULL_TREE
- && ! TREE_STATIC (decl))
+ && !TREE_STATIC (decl))
{
error ("%Jsection attribute cannot be specified for "
"local variables", decl);
&& strcmp (TREE_STRING_POINTER (DECL_SECTION_NAME (decl)),
TREE_STRING_POINTER (TREE_VALUE (args))) != 0)
{
- error ("%Jsection of '%D' conflicts with previous declaration",
+ error ("%Jsection of %qD conflicts with previous declaration",
*node, *node);
*no_add_attrs = true;
}
}
else
{
- error ("%Jsection attribute not allowed for '%D'", *node, *node);
+ error ("%Jsection attribute not allowed for %qD", *node, *node);
*no_add_attrs = true;
}
}
struct attribute_spec.handler. */
static tree
-handle_aligned_attribute (tree *node, tree name ATTRIBUTE_UNUSED, tree args,
+handle_aligned_attribute (tree *node, tree ARG_UNUSED (name), tree args,
int flags, bool *no_add_attrs)
{
tree decl = NULL_TREE;
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");
&& DECL_ORIGINAL_TYPE (decl) == NULL_TREE)
{
tree tt = TREE_TYPE (decl);
- *type = build_type_copy (*type);
+ *type = build_variant_type_copy (*type);
DECL_ORIGINAL_TYPE (decl) = tt;
TYPE_NAME (*type) = decl;
TREE_USED (*type) = TREE_USED (decl);
TREE_TYPE (decl) = *type;
}
else if (!(flags & (int) ATTR_FLAG_TYPE_IN_PLACE))
- *type = build_type_copy (*type);
+ *type = build_variant_type_copy (*type);
TYPE_ALIGN (*type) = (1 << i) * BITS_PER_UNIT;
TYPE_USER_ALIGN (*type) = 1;
else if (TREE_CODE (decl) != VAR_DECL
&& TREE_CODE (decl) != FIELD_DECL)
{
- error ("%Jalignment may not be specified for '%D'", decl, decl);
+ error ("%Jalignment may not be specified for %qD", decl, decl);
*no_add_attrs = true;
}
else
struct attribute_spec.handler. */
static tree
-handle_weak_attribute (tree *node, tree name ATTRIBUTE_UNUSED,
- tree args ATTRIBUTE_UNUSED,
- int flags ATTRIBUTE_UNUSED,
- bool *no_add_attrs ATTRIBUTE_UNUSED)
+handle_weak_attribute (tree *node, tree ARG_UNUSED (name),
+ tree ARG_UNUSED (args),
+ int ARG_UNUSED (flags),
+ bool * ARG_UNUSED (no_add_attrs))
{
declare_weak (*node);
static tree
handle_alias_attribute (tree *node, tree name, tree args,
- int flags ATTRIBUTE_UNUSED, bool *no_add_attrs)
+ int ARG_UNUSED (flags), bool *no_add_attrs)
{
tree decl = *node;
if ((TREE_CODE (decl) == FUNCTION_DECL && DECL_INITIAL (decl))
- || (TREE_CODE (decl) != FUNCTION_DECL && ! DECL_EXTERNAL (decl)))
+ || (TREE_CODE (decl) != FUNCTION_DECL && !DECL_EXTERNAL (decl)))
{
- error ("%J'%D' defined both normally and as an alias", decl, decl);
+ error ("%J%qD defined both normally and as an alias", decl, decl);
*no_add_attrs = true;
}
id = TREE_VALUE (args);
if (TREE_CODE (id) != STRING_CST)
{
- error ("alias arg not a string");
+ error ("alias argument not a string");
*no_add_attrs = true;
return NULL_TREE;
}
}
else
{
- warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
+ warning ("%qE attribute ignored", name);
*no_add_attrs = true;
}
static tree
handle_visibility_attribute (tree *node, tree name, tree args,
- int flags ATTRIBUTE_UNUSED,
+ int ARG_UNUSED (flags),
bool *no_add_attrs)
{
tree decl = *node;
*no_add_attrs = true;
- if (decl_function_context (decl) != 0 || ! TREE_PUBLIC (decl))
+ if (TYPE_P (*node))
+ {
+ if (TREE_CODE (*node) != RECORD_TYPE && TREE_CODE (*node) != UNION_TYPE)
+ {
+ warning ("%qE attribute ignored on non-class types", name);
+ return NULL_TREE;
+ }
+ }
+ else if (decl_function_context (decl) != 0 || !TREE_PUBLIC (decl))
{
- warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
+ warning ("%qE attribute ignored", name);
return NULL_TREE;
}
if (TREE_CODE (id) != STRING_CST)
{
- error ("visibility arg not a string");
+ error ("visibility argument not a string");
return NULL_TREE;
}
+ /* If this is a type, set the visibility on the type decl. */
+ if (TYPE_P (decl))
+ {
+ decl = TYPE_NAME (decl);
+ if (!decl)
+ return NULL_TREE;
+ if (TREE_CODE (decl) == IDENTIFIER_NODE)
+ {
+ warning ("%qE attribute ignored on types",
+ name);
+ return NULL_TREE;
+ }
+ }
+
if (strcmp (TREE_STRING_POINTER (id), "default") == 0)
DECL_VISIBILITY (decl) = VISIBILITY_DEFAULT;
else if (strcmp (TREE_STRING_POINTER (id), "internal") == 0)
DECL_VISIBILITY (decl) = VISIBILITY_INTERNAL;
else if (strcmp (TREE_STRING_POINTER (id), "hidden") == 0)
- DECL_VISIBILITY (decl) = VISIBILITY_HIDDEN;
+ DECL_VISIBILITY (decl) = VISIBILITY_HIDDEN;
else if (strcmp (TREE_STRING_POINTER (id), "protected") == 0)
DECL_VISIBILITY (decl) = VISIBILITY_PROTECTED;
else
- error ("visibility arg must be one of \"default\", \"hidden\", \"protected\" or \"internal\"");
+ error ("visibility argument must be one of \"default\", \"hidden\", \"protected\" or \"internal\"");
+ DECL_VISIBILITY_SPECIFIED (decl) = 1;
+
+ /* For decls only, go ahead and attach the attribute to the node as well.
+ This is needed so we can determine whether we have VISIBILITY_DEFAULT
+ because the visibility was not specified, or because it was explicitly
+ overridden from the class visibility. */
+ if (DECL_P (*node))
+ *no_add_attrs = false;
return NULL_TREE;
}
+/* Determine the ELF symbol visibility for DECL, which is either a
+ variable or a function. It is an error to use this function if a
+ definition of DECL is not available in this translation unit.
+ Returns true if the final visibility has been determined by this
+ function; false if the caller is free to make additional
+ modifications. */
+
+bool
+c_determine_visibility (tree decl)
+{
+ gcc_assert (TREE_CODE (decl) == VAR_DECL
+ || TREE_CODE (decl) == FUNCTION_DECL);
+
+ /* If the user explicitly specified the visibility with an
+ attribute, honor that. DECL_VISIBILITY will have been set during
+ the processing of the attribute. We check for an explicit
+ attribute, rather than just checking DECL_VISIBILITY_SPECIFIED,
+ to distinguish the use of an attribute from the use of a "#pragma
+ GCC visibility push(...)"; in the latter case we still want other
+ considerations to be able to overrule the #pragma. */
+ if (lookup_attribute ("visibility", DECL_ATTRIBUTES (decl)))
+ return true;
+
+ /* Anything that is exported must have default visibility. */
+ if (TARGET_DLLIMPORT_DECL_ATTRIBUTES
+ && lookup_attribute ("dllexport", DECL_ATTRIBUTES (decl)))
+ {
+ DECL_VISIBILITY (decl) = VISIBILITY_DEFAULT;
+ DECL_VISIBILITY_SPECIFIED (decl) = 1;
+ return true;
+ }
+
+ return false;
+}
+
/* Handle an "tls_model" attribute; arguments as in
struct attribute_spec.handler. */
static tree
handle_tls_model_attribute (tree *node, tree name, tree args,
- int flags ATTRIBUTE_UNUSED, bool *no_add_attrs)
+ int ARG_UNUSED (flags), bool *no_add_attrs)
{
tree decl = *node;
- if (! DECL_THREAD_LOCAL (decl))
+ if (!DECL_THREAD_LOCAL (decl))
{
- warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
+ warning ("%qE attribute ignored", name);
*no_add_attrs = true;
}
else
id = TREE_VALUE (args);
if (TREE_CODE (id) != STRING_CST)
{
- error ("tls_model arg not a string");
+ error ("tls_model argument not a string");
*no_add_attrs = true;
return NULL_TREE;
}
&& 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\"");
+ error ("tls_model argument must be one of \"local-exec\", \"initial-exec\", \"local-dynamic\" or \"global-dynamic\"");
*no_add_attrs = true;
return NULL_TREE;
}
static tree
handle_no_instrument_function_attribute (tree *node, tree name,
- tree args ATTRIBUTE_UNUSED,
- int flags ATTRIBUTE_UNUSED,
+ tree ARG_UNUSED (args),
+ int ARG_UNUSED (flags),
bool *no_add_attrs)
{
tree decl = *node;
if (TREE_CODE (decl) != FUNCTION_DECL)
{
- error ("%J'%E' attribute applies only to functions", decl, name);
+ error ("%J%qE attribute applies only to functions", decl, name);
*no_add_attrs = true;
}
else if (DECL_INITIAL (decl))
{
- error ("%Jcan't set '%E' attribute after definition", decl, name);
+ error ("%Jcan%'t set %qE attribute after definition", decl, name);
*no_add_attrs = true;
}
else
struct attribute_spec.handler. */
static tree
-handle_malloc_attribute (tree *node, tree name, tree args ATTRIBUTE_UNUSED,
- int flags ATTRIBUTE_UNUSED, bool *no_add_attrs)
+handle_malloc_attribute (tree *node, tree name, tree ARG_UNUSED (args),
+ int ARG_UNUSED (flags), bool *no_add_attrs)
{
if (TREE_CODE (*node) == FUNCTION_DECL)
DECL_IS_MALLOC (*node) = 1;
/* ??? TODO: Support types. */
else
{
- warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
+ warning ("%qE attribute ignored", name);
+ *no_add_attrs = true;
+ }
+
+ return NULL_TREE;
+}
+
+/* Handle a "returns_twice" attribute; arguments as in
+ struct attribute_spec.handler. */
+
+static tree
+handle_returns_twice_attribute (tree *node, tree name, tree ARG_UNUSED (args),
+ int ARG_UNUSED (flags), bool *no_add_attrs)
+{
+ if (TREE_CODE (*node) == FUNCTION_DECL)
+ DECL_IS_RETURNS_TWICE (*node) = 1;
+ else
+ {
+ warning ("%qE attribute ignored", name);
*no_add_attrs = true;
}
static tree
handle_no_limit_stack_attribute (tree *node, tree name,
- tree args ATTRIBUTE_UNUSED,
- int flags ATTRIBUTE_UNUSED,
+ tree ARG_UNUSED (args),
+ int ARG_UNUSED (flags),
bool *no_add_attrs)
{
tree decl = *node;
if (TREE_CODE (decl) != FUNCTION_DECL)
{
- error ("%J'%E' attribute applies only to functions", decl, name);
+ error ("%J%qE attribute applies only to functions", decl, name);
*no_add_attrs = true;
}
else if (DECL_INITIAL (decl))
{
- error ("%Jcan't set '%E' attribute after definition", decl, name);
+ error ("%Jcan%'t set %qE attribute after definition", decl, name);
*no_add_attrs = true;
}
else
struct attribute_spec.handler. */
static tree
-handle_pure_attribute (tree *node, tree name, tree args ATTRIBUTE_UNUSED,
- int flags ATTRIBUTE_UNUSED, bool *no_add_attrs)
+handle_pure_attribute (tree *node, tree name, tree ARG_UNUSED (args),
+ int ARG_UNUSED (flags), bool *no_add_attrs)
{
if (TREE_CODE (*node) == FUNCTION_DECL)
DECL_IS_PURE (*node) = 1;
/* ??? TODO: Support types. */
else
{
- warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
+ warning ("%qE attribute ignored", name);
*no_add_attrs = true;
}
return NULL_TREE;
}
+/* Handle a "no vops" attribute; arguments as in
+ struct attribute_spec.handler. */
+
+static tree
+handle_novops_attribute (tree *node, tree ARG_UNUSED (name),
+ tree ARG_UNUSED (args), int ARG_UNUSED (flags),
+ bool *ARG_UNUSED (no_add_attrs))
+{
+ gcc_assert (TREE_CODE (*node) == FUNCTION_DECL);
+ DECL_IS_NOVOPS (*node) = 1;
+ return NULL_TREE;
+}
+
/* Handle a "deprecated" attribute; arguments as in
struct attribute_spec.handler. */
static tree
handle_deprecated_attribute (tree *node, tree name,
- tree args ATTRIBUTE_UNUSED, int flags,
+ tree ARG_UNUSED (args), int flags,
bool *no_add_attrs)
{
tree type = NULL_TREE;
int warn = 0;
- const char *what = NULL;
+ tree what = NULL_TREE;
if (DECL_P (*node))
{
else if (TYPE_P (*node))
{
if (!(flags & (int) ATTR_FLAG_TYPE_IN_PLACE))
- *node = build_type_copy (*node);
+ *node = build_variant_type_copy (*node);
TREE_DEPRECATED (*node) = 1;
type = *node;
}
if (type && TYPE_NAME (type))
{
if (TREE_CODE (TYPE_NAME (type)) == IDENTIFIER_NODE)
- what = IDENTIFIER_POINTER (TYPE_NAME (*node));
+ what = TYPE_NAME (*node);
else if (TREE_CODE (TYPE_NAME (type)) == TYPE_DECL
&& DECL_NAME (TYPE_NAME (type)))
- what = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (type)));
+ what = DECL_NAME (TYPE_NAME (type));
}
if (what)
- warning ("`%s' attribute ignored for `%s'",
- IDENTIFIER_POINTER (name), what);
+ warning ("%qE attribute ignored for %qE", name, what);
else
- warning ("`%s' attribute ignored",
- IDENTIFIER_POINTER (name));
+ warning ("%qE attribute ignored", name);
}
return NULL_TREE;
static tree
handle_vector_size_attribute (tree *node, tree name, tree args,
- int flags ATTRIBUTE_UNUSED,
+ int ARG_UNUSED (flags),
bool *no_add_attrs)
{
unsigned HOST_WIDE_INT vecsize, nunits;
- enum machine_mode mode, orig_mode, new_mode;
+ enum machine_mode orig_mode;
tree type = *node, new_type, size;
*no_add_attrs = true;
- /* Stripping NON_LVALUE_EXPR allows declarations such as
- typedef short v4si __attribute__((vector_size (4 * sizeof(short)))). */
size = TREE_VALUE (args);
- if (TREE_CODE (size) == NON_LVALUE_EXPR)
- size = TREE_OPERAND (size, 0);
- if (! host_integerp (size, 1))
+ if (!host_integerp (size, 1))
{
- warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
+ warning ("%qE attribute ignored", name);
return NULL_TREE;
}
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))
+ || !host_integerp (TYPE_SIZE_UNIT (type), 1))
{
- error ("invalid vector type for attribute `%s'",
- IDENTIFIER_POINTER (name));
+ error ("invalid vector type for attribute %qE", name);
return NULL_TREE;
}
/* Calculate how many units fit in the vector. */
nunits = vecsize / tree_low_cst (TYPE_SIZE_UNIT (type), 1);
-
- /* Find a suitably sized vector. */
- new_mode = VOIDmode;
- for (mode = GET_CLASS_NARROWEST_MODE (GET_MODE_CLASS (orig_mode) == MODE_INT
- ? MODE_VECTOR_INT
- : MODE_VECTOR_FLOAT);
- mode != VOIDmode;
- mode = GET_MODE_WIDER_MODE (mode))
- if (vecsize == GET_MODE_SIZE (mode)
- && nunits == (unsigned HOST_WIDE_INT) GET_MODE_NUNITS (mode))
- {
- new_mode = mode;
- break;
- }
-
- if (new_mode == VOIDmode)
+ if (nunits & (nunits - 1))
{
- error ("no vector mode with the size and type specified could be found");
+ error ("number of components of the vector not a power of two");
return NULL_TREE;
}
- new_type = build_vector_type_for_mode (type, new_mode);
+ new_type = build_vector_type (type, nunits);
/* Build back pointers if needed. */
*node = reconstruct_complex_type (*node, new_type);
/* Handle the "nonnull" attribute. */
static tree
-handle_nonnull_attribute (tree *node, tree name ATTRIBUTE_UNUSED,
- tree args, int flags ATTRIBUTE_UNUSED,
+handle_nonnull_attribute (tree *node, tree ARG_UNUSED (name),
+ tree args, int ARG_UNUSED (flags),
bool *no_add_attrs)
{
tree type = *node;
/* If no arguments are specified, all pointer arguments should be
non-null. Verify a full prototype is given so that the arguments
will have the correct types when we actually check them later. */
- if (! args)
+ if (!args)
{
- if (! TYPE_ARG_TYPES (type))
+ if (!TYPE_ARG_TYPES (type))
{
error ("nonnull attribute without arguments on a non-prototype");
*no_add_attrs = true;
tree argument;
unsigned HOST_WIDE_INT arg_num = 0, ck_num;
- if (! get_nonnull_operand (TREE_VALUE (args), &arg_num))
+ if (!get_nonnull_operand (TREE_VALUE (args), &arg_num))
{
- error ("nonnull argument has invalid operand number (arg %lu)",
+ error ("nonnull argument has invalid operand number (argument %lu)",
(unsigned long) attr_arg_num);
*no_add_attrs = true;
return NULL_TREE;
{
for (ck_num = 1; ; ck_num++)
{
- if (! argument || ck_num == arg_num)
+ if (!argument || ck_num == arg_num)
break;
argument = TREE_CHAIN (argument);
}
- if (! argument
+ if (!argument
|| TREE_CODE (TREE_VALUE (argument)) == VOID_TYPE)
{
- error ("nonnull argument with out-of-range operand number (arg %lu, operand %lu)",
+ error ("nonnull argument with out-of-range operand number (argument %lu, operand %lu)",
(unsigned long) attr_arg_num, (unsigned long) arg_num);
*no_add_attrs = true;
return NULL_TREE;
if (TREE_CODE (TREE_VALUE (argument)) != POINTER_TYPE)
{
- error ("nonnull argument references non-pointer operand (arg %lu, operand %lu)",
+ error ("nonnull argument references non-pointer operand (argument %lu, operand %lu)",
(unsigned long) attr_arg_num, (unsigned long) arg_num);
*no_add_attrs = true;
return NULL_TREE;
for (param = params, param_num = 1; ;
param_num++, param = TREE_CHAIN (param))
{
- if (! param)
+ if (!param)
break;
- if (! args || nonnull_check_p (args, param_num))
+ if (!args || nonnull_check_p (args, param_num))
check_function_arguments_recurse (check_nonnull_arg, NULL,
TREE_VALUE (param),
param_num);
}
}
+/* Check that the Nth argument of a function call (counting backwards
+ from the end) is a (pointer)0. */
+
+static void
+check_function_sentinel (tree attrs, tree params)
+{
+ tree attr = lookup_attribute ("sentinel", attrs);
+
+ if (attr)
+ {
+ if (!params)
+ warning ("missing sentinel in function call");
+ else
+ {
+ tree sentinel, end;
+ unsigned pos = 0;
+
+ if (TREE_VALUE (attr))
+ {
+ tree p = TREE_VALUE (TREE_VALUE (attr));
+ pos = TREE_INT_CST_LOW (p);
+ }
+
+ sentinel = end = params;
+
+ /* Advance `end' ahead of `sentinel' by `pos' positions. */
+ while (pos > 0 && TREE_CHAIN (end))
+ {
+ pos--;
+ end = TREE_CHAIN (end);
+ }
+ if (pos > 0)
+ {
+ warning ("not enough arguments to fit a sentinel");
+ return;
+ }
+
+ /* Now advance both until we find the last parameter. */
+ while (TREE_CHAIN (end))
+ {
+ end = TREE_CHAIN (end);
+ sentinel = TREE_CHAIN (sentinel);
+ }
+
+ /* Validate the sentinel. */
+ if (!POINTER_TYPE_P (TREE_TYPE (TREE_VALUE (sentinel)))
+ || !integer_zerop (TREE_VALUE (sentinel)))
+ warning ("missing sentinel in function call");
+ }
+ }
+}
+
/* 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. */
for (; args; args = TREE_CHAIN (args))
{
- if (! get_nonnull_operand (TREE_VALUE (args), &arg_num))
- abort ();
+ bool found = get_nonnull_operand (TREE_VALUE (args), &arg_num);
+
+ gcc_assert (found);
if (arg_num == param_num)
return true;
via check_function_arguments_recurse. */
static void
-check_nonnull_arg (void *ctx ATTRIBUTE_UNUSED, tree param,
+check_nonnull_arg (void * ARG_UNUSED (ctx), tree param,
unsigned HOST_WIDE_INT param_num)
{
/* Just skip checking the argument if it's not a pointer. This can
return;
if (integer_zerop (param))
- warning ("null argument where non-null required (arg %lu)",
+ warning ("null argument where non-null required (argument %lu)",
(unsigned long) param_num);
}
static bool
get_nonnull_operand (tree arg_num_expr, unsigned HOST_WIDE_INT *valp)
{
- /* Strip any conversions from the arg number and verify they
- are constants. */
- while (TREE_CODE (arg_num_expr) == NOP_EXPR
- || TREE_CODE (arg_num_expr) == CONVERT_EXPR
- || TREE_CODE (arg_num_expr) == NON_LVALUE_EXPR)
- arg_num_expr = TREE_OPERAND (arg_num_expr, 0);
-
+ /* Verify the arg number is a constant. */
if (TREE_CODE (arg_num_expr) != INTEGER_CST
|| TREE_INT_CST_HIGH (arg_num_expr) != 0)
return false;
struct attribute_spec.handler. */
static tree
-handle_nothrow_attribute (tree *node, tree name, tree args ATTRIBUTE_UNUSED,
- int flags ATTRIBUTE_UNUSED, bool *no_add_attrs)
+handle_nothrow_attribute (tree *node, tree name, tree ARG_UNUSED (args),
+ int ARG_UNUSED (flags), bool *no_add_attrs)
{
if (TREE_CODE (*node) == FUNCTION_DECL)
TREE_NOTHROW (*node) = 1;
/* ??? TODO: Support types. */
else
{
- warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
+ warning ("%qE attribute ignored", name);
*no_add_attrs = true;
}
static tree
handle_cleanup_attribute (tree *node, tree name, tree args,
- int flags ATTRIBUTE_UNUSED, bool *no_add_attrs)
+ int ARG_UNUSED (flags), bool *no_add_attrs)
{
tree decl = *node;
tree cleanup_id, cleanup_decl;
we'd be missing too much, since we do have attribute constructor. */
if (TREE_CODE (decl) != VAR_DECL || TREE_STATIC (decl))
{
- warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
+ warning ("%qE attribute ignored", name);
*no_add_attrs = true;
return NULL_TREE;
}
cleanup_id = TREE_VALUE (args);
if (TREE_CODE (cleanup_id) != IDENTIFIER_NODE)
{
- error ("cleanup arg not an identifier");
+ error ("cleanup argument not an identifier");
*no_add_attrs = true;
return NULL_TREE;
}
cleanup_decl = lookup_name (cleanup_id);
if (!cleanup_decl || TREE_CODE (cleanup_decl) != FUNCTION_DECL)
{
- error ("cleanup arg not a function");
+ error ("cleanup argument not a function");
*no_add_attrs = true;
return NULL_TREE;
}
static tree
handle_warn_unused_result_attribute (tree *node, tree name,
- tree args ATTRIBUTE_UNUSED,
- int flags ATTRIBUTE_UNUSED, bool *no_add_attrs)
+ tree ARG_UNUSED (args),
+ int ARG_UNUSED (flags), bool *no_add_attrs)
{
/* Ignore the attribute for functions not returning any value. */
if (VOID_TYPE_P (TREE_TYPE (*node)))
{
- warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
+ warning ("%qE attribute ignored", name);
*no_add_attrs = true;
}
return NULL_TREE;
}
+
+/* Handle a "sentinel" attribute. */
+
+static tree
+handle_sentinel_attribute (tree *node, tree name, tree args,
+ int ARG_UNUSED (flags), bool *no_add_attrs)
+{
+ tree params = TYPE_ARG_TYPES (*node);
+
+ if (!params)
+ {
+ warning ("%qE attribute requires prototypes with named arguments", name);
+ *no_add_attrs = true;
+ }
+ else
+ {
+ while (TREE_CHAIN (params))
+ params = TREE_CHAIN (params);
+
+ if (VOID_TYPE_P (TREE_VALUE (params)))
+ {
+ warning ("%qE attribute only applies to variadic functions", name);
+ *no_add_attrs = true;
+ }
+ }
+
+ if (args)
+ {
+ tree position = TREE_VALUE (args);
+
+ if (TREE_CODE (position) != INTEGER_CST)
+ {
+ warning ("requested position is not an integer constant");
+ *no_add_attrs = true;
+ }
+ else
+ {
+ if (tree_int_cst_lt (position, integer_zero_node))
+ {
+ warning ("requested position is less than zero");
+ *no_add_attrs = true;
+ }
+ }
+ }
+
+ return NULL_TREE;
+}
\f
/* Check for valid arguments being passed to a function. */
void
/* Check for errors in format strings. */
if (warn_format)
- check_function_format (NULL, attrs, params);
+ {
+ check_function_format (attrs, params);
+ check_function_sentinel (attrs, params);
+ }
}
/* Generic argument checking recursion routine. PARAM is the argument to
/* Extract the argument number, which was previously checked
to be valid. */
format_num_expr = TREE_VALUE (TREE_VALUE (attrs));
- while (TREE_CODE (format_num_expr) == NOP_EXPR
- || TREE_CODE (format_num_expr) == CONVERT_EXPR
- || TREE_CODE (format_num_expr) == NON_LVALUE_EXPR)
- format_num_expr = TREE_OPERAND (format_num_expr, 0);
- if (TREE_CODE (format_num_expr) != INTEGER_CST
- || TREE_INT_CST_HIGH (format_num_expr) != 0)
- abort ();
+ gcc_assert (TREE_CODE (format_num_expr) == INTEGER_CST
+ && !TREE_INT_CST_HIGH (format_num_expr));
format_num = TREE_INT_CST_LOW (format_num_expr);
(*callback) (ctx, param, param_num);
}
-/* C implementation of lang_hooks.tree_inlining.walk_subtrees. Tracks the
- locus from EXPR_LOCUS and handles DECL_STMT specially. */
-
-tree
-c_walk_subtrees (tree *tp, int *walk_subtrees_p ATTRIBUTE_UNUSED,
- walk_tree_fn func, void *data, void *htab)
-{
- enum tree_code code = TREE_CODE (*tp);
- location_t save_locus;
- tree result;
-
-#define WALK_SUBTREE(NODE) \
- do \
- { \
- result = walk_tree (&(NODE), func, data, htab); \
- if (result) goto out; \
- } \
- while (0)
-
- if (code != DECL_STMT)
- return NULL_TREE;
-
- /* Set input_location here so we get the right instantiation context
- if we call instantiate_decl from inlinable_function_p. */
- save_locus = input_location;
- if (EXPR_LOCUS (*tp))
- input_location = *EXPR_LOCUS (*tp);
-
- /* Walk the DECL_INITIAL and DECL_SIZE. We don't want to walk
- into declarations that are just mentioned, rather than
- declared; they don't really belong to this part of the tree.
- And, we can see cycles: the initializer for a declaration can
- refer to the declaration itself. */
- WALK_SUBTREE (DECL_INITIAL (DECL_STMT_DECL (*tp)));
- WALK_SUBTREE (DECL_SIZE (DECL_STMT_DECL (*tp)));
- WALK_SUBTREE (DECL_SIZE_UNIT (DECL_STMT_DECL (*tp)));
- WALK_SUBTREE (TREE_CHAIN (*tp));
- *walk_subtrees_p = 0;
-
- /* We didn't find what we were looking for. */
- out:
- input_location = save_locus;
- return result;
-
-#undef WALK_SUBTREE
-}
-
/* Function to help qsort sort FIELD_DECLs by name order. */
int
field_decl_cmp (const void *x_p, const void *y_p)
{
- const tree *const x = x_p;
- const tree *const y = y_p;
+ const tree *const x = (const tree *const) x_p;
+ const tree *const y = (const tree *const) y_p;
+
if (DECL_NAME (*x) == DECL_NAME (*y))
/* A nontype is "greater" than a type. */
return (TREE_CODE (*y) == TYPE_DECL) - (TREE_CODE (*x) == TYPE_DECL);
static int
resort_field_decl_cmp (const void *x_p, const void *y_p)
{
- const tree *const x = x_p;
- const tree *const y = y_p;
+ const tree *const x = (const tree *const) x_p;
+ const tree *const y = (const tree *const) y_p;
if (DECL_NAME (*x) == DECL_NAME (*y))
/* A nontype is "greater" than a type. */
void
resort_sorted_fields (void *obj,
- void *orig_obj ATTRIBUTE_UNUSED ,
+ void * ARG_UNUSED (orig_obj),
gt_pointer_operator new_value,
void *cookie)
{
- struct sorted_fields_type *sf = obj;
+ struct sorted_fields_type *sf = (struct sorted_fields_type *) obj;
resort_data.new_value = new_value;
resort_data.cookie = cookie;
qsort (&sf->elts[0], sf->len, sizeof (tree),
resort_field_decl_cmp);
}
+/* Subroutine of c_parse_error.
+ Return the result of concatenating LHS and RHS. RHS is really
+ a string literal, its first character is indicated by RHS_START and
+ RHS_SIZE is its length (including the terminating NUL character).
+
+ The caller is responsible for deleting the returned pointer. */
+
+static char *
+catenate_strings (const char *lhs, const char *rhs_start, int rhs_size)
+{
+ const int lhs_size = strlen (lhs);
+ char *result = XNEWVEC (char, lhs_size + rhs_size);
+ strncpy (result, lhs, lhs_size);
+ strncpy (result + lhs_size, rhs_start, rhs_size);
+ return result;
+}
+
/* Issue the error given by MSGID, indicating that it occurred before
TOKEN, which had the associated VALUE. */
void
c_parse_error (const char *msgid, enum cpp_ttype token, tree value)
{
- const char *string = _(msgid);
+#define catenate_messages(M1, M2) catenate_strings ((M1), (M2), sizeof (M2))
+
+ char *message = NULL;
if (token == CPP_EOF)
- error ("%s at end of input", string);
+ message = catenate_messages (msgid, " at end of input");
else if (token == CPP_CHAR || token == CPP_WCHAR)
{
unsigned int val = TREE_INT_CST_LOW (value);
const char *const ell = (token == CPP_CHAR) ? "" : "L";
if (val <= UCHAR_MAX && ISGRAPH (val))
- error ("%s before %s'%c'", string, ell, val);
+ message = catenate_messages (msgid, " before %s'%c'");
else
- error ("%s before %s'\\x%x'", string, ell, val);
+ message = catenate_messages (msgid, " before %s'\\x%x'");
+
+ error (message, ell, val);
+ free (message);
+ message = NULL;
}
- else if (token == CPP_STRING
- || token == CPP_WSTRING)
- error ("%s before string constant", string);
+ else if (token == CPP_STRING || token == CPP_WSTRING)
+ message = catenate_messages (msgid, " before string constant");
else if (token == CPP_NUMBER)
- error ("%s before numeric constant", string);
+ message = catenate_messages (msgid, " before numeric constant");
else if (token == CPP_NAME)
- error ("%s before \"%s\"", string, IDENTIFIER_POINTER (value));
+ {
+ message = catenate_messages (msgid, " before %qE");
+ error (message, value);
+ free (message);
+ message = NULL;
+ }
else if (token < N_TTYPES)
- error ("%s before '%s' token", string, cpp_type2name (token));
+ {
+ message = catenate_messages (msgid, " before %qs token");
+ error (message, cpp_type2name (token));
+ free (message);
+ message = NULL;
+ }
else
- error ("%s", string);
+ error (msgid);
+
+ if (message)
+ {
+ error (message);
+ free (message);
+ }
+#undef catenate_messages
}
/* Walk a gimplified function and warn for functions whose return value is
ignored and attribute((warn_unused_result)) is set. This is done before
- inlining, so we don't have to worry about that. */
-
+ inlining, so we don't have to worry about that. */
+
void
c_warn_unused_result (tree *top_p)
{
break;
case CALL_EXPR:
+ if (TREE_USED (t))
+ break;
+
/* This is a naked call, as opposed to a CALL_EXPR nested inside
a MODIFY_EXPR. All calls whose value is ignored should be
represented like this. Look for the attribute. */
if (lookup_attribute ("warn_unused_result", TYPE_ATTRIBUTES (ftype)))
{
if (fdecl)
- warning ("%Hignoring return value of `%D', "
+ warning ("%Hignoring return value of %qD, "
"declared with attribute warn_unused_result",
EXPR_LOCUS (t), fdecl);
else
}
}
+/* Convert a character from the host to the target execution character
+ set. cpplib handles this, mostly. */
+
+HOST_WIDE_INT
+c_common_to_target_charset (HOST_WIDE_INT c)
+{
+ /* Character constants in GCC proper are sign-extended under -fsigned-char,
+ zero-extended under -fno-signed-char. cpplib insists that characters
+ and character constants are always unsigned. Hence we must convert
+ back and forth. */
+ cppchar_t uc = ((cppchar_t)c) & ((((cppchar_t)1) << CHAR_BIT)-1);
+
+ uc = cpp_host_to_exec_charset (parse_in, uc);
+
+ if (flag_signed_char)
+ return ((HOST_WIDE_INT)uc) << (HOST_BITS_PER_WIDE_INT - CHAR_TYPE_SIZE)
+ >> (HOST_BITS_PER_WIDE_INT - CHAR_TYPE_SIZE);
+ else
+ return uc;
+}
+
+/* Build the result of __builtin_offsetof. EXPR is a nested sequence of
+ component references, with an INDIRECT_REF at the bottom; much like
+ the traditional rendering of offsetof as a macro. Returns the folded
+ and properly cast result. */
+
+static tree
+fold_offsetof_1 (tree expr)
+{
+ enum tree_code code = PLUS_EXPR;
+ tree base, off, t;
+
+ switch (TREE_CODE (expr))
+ {
+ case ERROR_MARK:
+ return expr;
+
+ case INDIRECT_REF:
+ return size_zero_node;
+
+ case COMPONENT_REF:
+ base = fold_offsetof_1 (TREE_OPERAND (expr, 0));
+ if (base == error_mark_node)
+ return base;
+
+ t = TREE_OPERAND (expr, 1);
+ if (DECL_C_BIT_FIELD (t))
+ {
+ error ("attempt to take address of bit-field structure "
+ "member %qD", t);
+ return error_mark_node;
+ }
+ off = size_binop (PLUS_EXPR, DECL_FIELD_OFFSET (t),
+ size_int (tree_low_cst (DECL_FIELD_BIT_OFFSET (t), 1)
+ / BITS_PER_UNIT));
+ break;
+
+ case ARRAY_REF:
+ base = fold_offsetof_1 (TREE_OPERAND (expr, 0));
+ if (base == error_mark_node)
+ return base;
+
+ t = TREE_OPERAND (expr, 1);
+ if (TREE_CODE (t) == INTEGER_CST && tree_int_cst_sgn (t) < 0)
+ {
+ code = MINUS_EXPR;
+ t = fold (build1 (NEGATE_EXPR, TREE_TYPE (t), t));
+ }
+ t = convert (sizetype, t);
+ off = size_binop (MULT_EXPR, TYPE_SIZE_UNIT (TREE_TYPE (expr)), t);
+ break;
+
+ default:
+ gcc_unreachable ();
+ }
+
+ return size_binop (code, base, off);
+}
+
+tree
+fold_offsetof (tree expr)
+{
+ /* Convert back from the internal sizetype to size_t. */
+ return convert (size_type_node, fold_offsetof_1 (expr));
+}
+
+/* Print an error message for an invalid lvalue. USE says
+ how the lvalue is being used and so selects the error message. */
+
+void
+lvalue_error (enum lvalue_use use)
+{
+ switch (use)
+ {
+ case lv_assign:
+ error ("invalid lvalue in assignment");
+ break;
+ case lv_increment:
+ error ("invalid lvalue in increment");
+ break;
+ case lv_decrement:
+ error ("invalid lvalue in decrement");
+ break;
+ case lv_addressof:
+ error ("invalid lvalue in unary %<&%>");
+ break;
+ case lv_asm:
+ error ("invalid lvalue in asm statement");
+ break;
+ default:
+ gcc_unreachable ();
+ }
+}
+\f
+/* *PTYPE is an incomplete array. Complete it with a domain based on
+ INITIAL_VALUE. If INITIAL_VALUE is not present, use 1 if DO_DEFAULT
+ is true. Return 0 if successful, 1 if INITIAL_VALUE can't be deciphered,
+ 2 if INITIAL_VALUE was NULL, and 3 if INITIAL_VALUE was empty. */
+
+int
+complete_array_type (tree *ptype, tree initial_value, bool do_default)
+{
+ tree maxindex, type, main_type, elt, unqual_elt;
+ int failure = 0, quals;
+
+ maxindex = size_zero_node;
+ if (initial_value)
+ {
+ if (TREE_CODE (initial_value) == STRING_CST)
+ {
+ int eltsize
+ = int_size_in_bytes (TREE_TYPE (TREE_TYPE (initial_value)));
+ maxindex = size_int (TREE_STRING_LENGTH (initial_value)/eltsize - 1);
+ }
+ else if (TREE_CODE (initial_value) == CONSTRUCTOR)
+ {
+ tree elts = CONSTRUCTOR_ELTS (initial_value);
+
+ if (elts == NULL)
+ {
+ if (pedantic)
+ failure = 3;
+ maxindex = integer_minus_one_node;
+ }
+ else
+ {
+ tree curindex;
+
+ if (TREE_PURPOSE (elts))
+ maxindex = fold_convert (sizetype, TREE_PURPOSE (elts));
+ curindex = maxindex;
+
+ for (elts = TREE_CHAIN (elts); elts; elts = TREE_CHAIN (elts))
+ {
+ if (TREE_PURPOSE (elts))
+ curindex = fold_convert (sizetype, TREE_PURPOSE (elts));
+ else
+ curindex = size_binop (PLUS_EXPR, curindex, size_one_node);
+
+ if (tree_int_cst_lt (maxindex, curindex))
+ maxindex = curindex;
+ }
+ }
+ }
+ else
+ {
+ /* Make an error message unless that happened already. */
+ if (initial_value != error_mark_node)
+ failure = 1;
+ }
+ }
+ else
+ {
+ failure = 2;
+ if (!do_default)
+ return failure;
+ }
+
+ type = *ptype;
+ elt = TREE_TYPE (type);
+ quals = TYPE_QUALS (strip_array_types (elt));
+ if (quals == 0)
+ unqual_elt = elt;
+ else
+ unqual_elt = c_build_qualified_type (elt, TYPE_UNQUALIFIED);
+
+ /* Using build_distinct_type_copy and modifying things afterward instead
+ of using build_array_type to create a new type preserves all of the
+ TYPE_LANG_FLAG_? bits that the front end may have set. */
+ main_type = build_distinct_type_copy (TYPE_MAIN_VARIANT (type));
+ TREE_TYPE (main_type) = unqual_elt;
+ TYPE_DOMAIN (main_type) = build_index_type (maxindex);
+ layout_type (main_type);
+
+ if (quals == 0)
+ type = main_type;
+ else
+ type = c_build_qualified_type (main_type, quals);
+
+ *ptype = type;
+ return failure;
+}
+
#include "gt-c-common.h"