1994-08-02 20:15:59 +00:00
|
|
|
|
/* Subroutines shared by all languages that are variants of C.
|
|
|
|
|
Copyright (C) 1992, 1993, 1994 Free Software Foundation, Inc.
|
|
|
|
|
|
|
|
|
|
This file is part of GNU CC.
|
|
|
|
|
|
|
|
|
|
GNU CC is free software; you can redistribute it and/or modify
|
|
|
|
|
it under the terms of the GNU General Public License as published by
|
|
|
|
|
the Free Software Foundation; either version 2, or (at your option)
|
|
|
|
|
any later version.
|
|
|
|
|
|
|
|
|
|
GNU CC is distributed in the hope that it will be useful,
|
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
|
GNU General Public License for more details.
|
|
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
|
along with GNU CC; see the file COPYING. If not, write to
|
|
|
|
|
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
|
|
|
|
|
|
|
|
|
|
#include "config.h"
|
|
|
|
|
#include "tree.h"
|
|
|
|
|
#include "c-lex.h"
|
|
|
|
|
#include "c-tree.h"
|
|
|
|
|
#include "flags.h"
|
|
|
|
|
#include "obstack.h"
|
|
|
|
|
#include <stdio.h>
|
|
|
|
|
#include <ctype.h>
|
|
|
|
|
|
|
|
|
|
extern struct obstack permanent_obstack;
|
|
|
|
|
|
|
|
|
|
static void declare_hidden_char_array PROTO((char *, char *));
|
|
|
|
|
|
|
|
|
|
/* Make bindings for __FUNCTION__ and __PRETTY_FUNCTION__. */
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
declare_function_name ()
|
|
|
|
|
{
|
|
|
|
|
char *name, *printable_name;
|
|
|
|
|
|
|
|
|
|
if (current_function_decl == NULL)
|
|
|
|
|
{
|
|
|
|
|
name = "";
|
|
|
|
|
printable_name = "top level";
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
char *kind = "function";
|
|
|
|
|
if (TREE_CODE (TREE_TYPE (current_function_decl)) == METHOD_TYPE)
|
|
|
|
|
kind = "method";
|
|
|
|
|
/* Allow functions to be nameless (such as artificial ones). */
|
|
|
|
|
if (DECL_NAME (current_function_decl))
|
|
|
|
|
name = IDENTIFIER_POINTER (DECL_NAME (current_function_decl));
|
|
|
|
|
else
|
|
|
|
|
name = "";
|
|
|
|
|
printable_name = (*decl_printable_name) (current_function_decl, &kind);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
declare_hidden_char_array ("__FUNCTION__", name);
|
|
|
|
|
declare_hidden_char_array ("__PRETTY_FUNCTION__", printable_name);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
declare_hidden_char_array (name, value)
|
|
|
|
|
char *name, *value;
|
|
|
|
|
{
|
|
|
|
|
tree decl, type, init;
|
|
|
|
|
int vlen;
|
|
|
|
|
|
|
|
|
|
/* If the default size of char arrays isn't big enough for the name,
|
|
|
|
|
or if we want to give warnings for large objects, make a bigger one. */
|
|
|
|
|
vlen = strlen (value) + 1;
|
|
|
|
|
type = char_array_type_node;
|
|
|
|
|
if (TREE_INT_CST_LOW (TYPE_MAX_VALUE (TREE_TYPE (type))) < vlen
|
|
|
|
|
|| warn_larger_than)
|
|
|
|
|
type = build_array_type (char_type_node,
|
|
|
|
|
build_index_type (build_int_2 (vlen, 0)));
|
|
|
|
|
push_obstacks_nochange ();
|
|
|
|
|
decl = build_decl (VAR_DECL, get_identifier (name), type);
|
|
|
|
|
TREE_STATIC (decl) = 1;
|
|
|
|
|
TREE_READONLY (decl) = 1;
|
|
|
|
|
TREE_ASM_WRITTEN (decl) = 1;
|
|
|
|
|
DECL_SOURCE_LINE (decl) = 0;
|
|
|
|
|
DECL_IN_SYSTEM_HEADER (decl) = 1;
|
|
|
|
|
DECL_IGNORED_P (decl) = 1;
|
|
|
|
|
init = build_string (vlen, value);
|
|
|
|
|
TREE_TYPE (init) = type;
|
|
|
|
|
DECL_INITIAL (decl) = init;
|
|
|
|
|
finish_decl (pushdecl (decl), init, NULL_TREE);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Given a chain of STRING_CST nodes,
|
|
|
|
|
concatenate them into one STRING_CST
|
|
|
|
|
and give it a suitable array-of-chars data type. */
|
|
|
|
|
|
|
|
|
|
tree
|
|
|
|
|
combine_strings (strings)
|
|
|
|
|
tree strings;
|
|
|
|
|
{
|
|
|
|
|
register tree value, t;
|
|
|
|
|
register int length = 1;
|
|
|
|
|
int wide_length = 0;
|
|
|
|
|
int wide_flag = 0;
|
|
|
|
|
int wchar_bytes = TYPE_PRECISION (wchar_type_node) / BITS_PER_UNIT;
|
|
|
|
|
int nchars;
|
|
|
|
|
|
|
|
|
|
if (TREE_CHAIN (strings))
|
|
|
|
|
{
|
|
|
|
|
/* More than one in the chain, so concatenate. */
|
|
|
|
|
register char *p, *q;
|
|
|
|
|
|
|
|
|
|
/* Don't include the \0 at the end of each substring,
|
|
|
|
|
except for the last one.
|
|
|
|
|
Count wide strings and ordinary strings separately. */
|
|
|
|
|
for (t = strings; t; t = TREE_CHAIN (t))
|
|
|
|
|
{
|
|
|
|
|
if (TREE_TYPE (t) == wchar_array_type_node)
|
|
|
|
|
{
|
|
|
|
|
wide_length += (TREE_STRING_LENGTH (t) - wchar_bytes);
|
|
|
|
|
wide_flag = 1;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
length += (TREE_STRING_LENGTH (t) - 1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* If anything is wide, the non-wides will be converted,
|
|
|
|
|
which makes them take more space. */
|
|
|
|
|
if (wide_flag)
|
|
|
|
|
length = length * wchar_bytes + wide_length;
|
|
|
|
|
|
|
|
|
|
p = savealloc (length);
|
|
|
|
|
|
|
|
|
|
/* Copy the individual strings into the new combined string.
|
|
|
|
|
If the combined string is wide, convert the chars to ints
|
|
|
|
|
for any individual strings that are not wide. */
|
|
|
|
|
|
|
|
|
|
q = p;
|
|
|
|
|
for (t = strings; t; t = TREE_CHAIN (t))
|
|
|
|
|
{
|
|
|
|
|
int len = (TREE_STRING_LENGTH (t)
|
|
|
|
|
- ((TREE_TYPE (t) == wchar_array_type_node)
|
|
|
|
|
? wchar_bytes : 1));
|
|
|
|
|
if ((TREE_TYPE (t) == wchar_array_type_node) == wide_flag)
|
|
|
|
|
{
|
|
|
|
|
bcopy (TREE_STRING_POINTER (t), q, len);
|
|
|
|
|
q += len;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
int i;
|
|
|
|
|
for (i = 0; i < len; i++)
|
|
|
|
|
((int *) q)[i] = TREE_STRING_POINTER (t)[i];
|
|
|
|
|
q += len * wchar_bytes;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (wide_flag)
|
|
|
|
|
{
|
|
|
|
|
int i;
|
|
|
|
|
for (i = 0; i < wchar_bytes; i++)
|
|
|
|
|
*q++ = 0;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
*q = 0;
|
|
|
|
|
|
|
|
|
|
value = make_node (STRING_CST);
|
|
|
|
|
TREE_STRING_POINTER (value) = p;
|
|
|
|
|
TREE_STRING_LENGTH (value) = length;
|
|
|
|
|
TREE_CONSTANT (value) = 1;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
value = strings;
|
|
|
|
|
length = TREE_STRING_LENGTH (value);
|
|
|
|
|
if (TREE_TYPE (value) == wchar_array_type_node)
|
|
|
|
|
wide_flag = 1;
|
|
|
|
|
}
|
|
|
|
|
|
1995-05-30 05:05:38 +00:00
|
|
|
|
/* Compute the number of elements, for the array type. */
|
1994-08-02 20:15:59 +00:00
|
|
|
|
nchars = wide_flag ? length / wchar_bytes : length;
|
|
|
|
|
|
|
|
|
|
/* 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. */
|
|
|
|
|
if (warn_write_strings
|
|
|
|
|
&& (! flag_traditional && ! flag_writable_strings))
|
|
|
|
|
{
|
|
|
|
|
tree elements
|
|
|
|
|
= build_type_variant (wide_flag ? wchar_type_node : char_type_node,
|
|
|
|
|
1, 0);
|
|
|
|
|
TREE_TYPE (value)
|
|
|
|
|
= build_array_type (elements,
|
|
|
|
|
build_index_type (build_int_2 (nchars - 1, 0)));
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
TREE_TYPE (value)
|
|
|
|
|
= build_array_type (wide_flag ? wchar_type_node : char_type_node,
|
|
|
|
|
build_index_type (build_int_2 (nchars - 1, 0)));
|
|
|
|
|
TREE_CONSTANT (value) = 1;
|
|
|
|
|
TREE_STATIC (value) = 1;
|
|
|
|
|
return value;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Process the attributes listed in ATTRIBUTES
|
|
|
|
|
and install them in DECL. */
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
decl_attributes (decl, attributes)
|
|
|
|
|
tree decl, attributes;
|
|
|
|
|
{
|
|
|
|
|
tree a, name, args, type, new_attr;
|
|
|
|
|
|
|
|
|
|
type = TREE_TYPE (decl);
|
|
|
|
|
|
|
|
|
|
new_attr = TYPE_ATTRIBUTES (type);
|
|
|
|
|
|
|
|
|
|
for (a = attributes; a; a = TREE_CHAIN (a))
|
|
|
|
|
if (!(name = TREE_VALUE (a)))
|
|
|
|
|
continue;
|
1994-11-15 04:52:19 +00:00
|
|
|
|
else if (name == get_identifier ("packed")
|
|
|
|
|
|| name == get_identifier ("__packed__"))
|
1994-08-02 20:15:59 +00:00
|
|
|
|
{
|
|
|
|
|
if (TREE_CODE (decl) == FIELD_DECL)
|
|
|
|
|
DECL_PACKED (decl) = 1;
|
|
|
|
|
/* We can't set DECL_PACKED for a VAR_DECL, because the bit is
|
|
|
|
|
used for DECL_REGISTER. It wouldn't mean anything anyway. */
|
|
|
|
|
else
|
|
|
|
|
warning_with_decl (decl, "`packed' attribute ignore");
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
else if (TREE_VALUE (a) == get_identifier ("noreturn")
|
1994-11-15 04:52:19 +00:00
|
|
|
|
|| TREE_VALUE (a) == get_identifier ("__noreturn__")
|
|
|
|
|
|| TREE_VALUE (a) == get_identifier ("volatile")
|
|
|
|
|
|| TREE_VALUE (a) == get_identifier ("__volatile__"))
|
1994-08-02 20:15:59 +00:00
|
|
|
|
{
|
|
|
|
|
if (TREE_CODE (decl) == FUNCTION_DECL)
|
|
|
|
|
TREE_THIS_VOLATILE (decl) = 1;
|
|
|
|
|
else if (TREE_CODE (type) == POINTER_TYPE
|
|
|
|
|
&& TREE_CODE (TREE_TYPE (type)) == FUNCTION_TYPE)
|
1995-05-30 05:05:38 +00:00
|
|
|
|
TREE_TYPE (decl) = type
|
1994-08-02 20:15:59 +00:00
|
|
|
|
= build_pointer_type
|
|
|
|
|
(build_type_variant (TREE_TYPE (type),
|
|
|
|
|
TREE_READONLY (TREE_TYPE (type)), 1));
|
|
|
|
|
else
|
|
|
|
|
warning_with_decl (decl, "`%s' attribute ignored",
|
|
|
|
|
IDENTIFIER_POINTER (TREE_VALUE (a)));
|
|
|
|
|
}
|
1994-11-15 04:52:19 +00:00
|
|
|
|
else if (TREE_VALUE (a) == get_identifier ("const")
|
|
|
|
|
|| TREE_VALUE (a) == get_identifier ("__const__"))
|
1994-08-02 20:15:59 +00:00
|
|
|
|
{
|
|
|
|
|
if (TREE_CODE (decl) == FUNCTION_DECL)
|
|
|
|
|
TREE_READONLY (decl) = 1;
|
|
|
|
|
else if (TREE_CODE (type) == POINTER_TYPE
|
|
|
|
|
&& TREE_CODE (TREE_TYPE (type)) == FUNCTION_TYPE)
|
|
|
|
|
TREE_TYPE (decl) = type
|
|
|
|
|
= build_pointer_type
|
|
|
|
|
(build_type_variant (TREE_TYPE (type), 1,
|
|
|
|
|
TREE_THIS_VOLATILE (TREE_TYPE (type))));
|
|
|
|
|
else
|
|
|
|
|
warning_with_decl (decl, "`const' attribute ignored");
|
|
|
|
|
}
|
1994-11-15 04:52:19 +00:00
|
|
|
|
else if (TREE_VALUE (a) == get_identifier ("transparent_union")
|
|
|
|
|
|| TREE_VALUE (a) == get_identifier ("__transparent_union__"))
|
----------------------------------
GCC-2.6.1 COMES TO FREEBSD-current
----------------------------------
Everybody needs to 'make world'.
Oakland, Nov 2nd 1994. In a surprise move this sunny afternoon, the release-
engineer for the slightly delayed FreeBSD-2.0, Poul-Henning Kamp (28),
decided to pull in the new version 2.6.1 of the GNU C-compiler.
The new version of the compiler was release today at noon, and hardly 9
hours later it was committed into the FreeBSD-current source-repository.
"It's is simply because we have had too much trouble with the version 2.6.0
of the compiler" Poul-Henning told the FreeBSD-Gazette, "we took a gamble
when we decided to use that as our compiler for the 2.0 release, but it
seems to pay of in the end now" he concludes.
The move has not been discussed on the "core" list at all, and will come as
a surprise for most Poul-Hennings peers. "I have only discussed it with
Jordan [J. K. Hubbard, the FreeBSD's resident humourist], and we agreed that
we needed to do it, so ... I did it!". After a breath he added with a grin:
"My email will probably get an all time 'disk-full' now!".
This will bring quite a flag-day to the FreeBSD developers, the patch-file
is almost 1.4 Megabyte, and they will have to run "make world" to get
entirely -current again. "Too bad, but we just had to do this." Was
the only comment from Poul-Henning to these problems.
When asked how this move would impact the 2.0 release-date, Poul-Hennings
face grew dark, he mumbled some very Danish words while he moved his fingers
in strange geometrical patterns. Immediately something ecclipsed the Sun, a
minor tremor shook the buildings, and the temperature fell significantly.
We decided not to pursure the question.
-----------
JOB-SECTION
-----------
Are you a dedicated GCC-hacker ?
We BADLY need somebody to look at the 'freebsd' OS in gcc, sanitize it and
carry the patches back to the GNU people. In particular, we need to get
out of the "i386-only" spot we are in now. I have the stuff to take a
gnu-dist into bmake-form, and will do that part.
Please apply to phk@freebsd.org
No Novice Need Apply.
1994-11-03 06:52:42 +00:00
|
|
|
|
{
|
|
|
|
|
if (TREE_CODE (decl) == PARM_DECL
|
|
|
|
|
&& TREE_CODE (type) == UNION_TYPE
|
|
|
|
|
&& TYPE_MODE (type) == DECL_MODE (TYPE_FIELDS (type)))
|
|
|
|
|
DECL_TRANSPARENT_UNION (decl) = 1;
|
|
|
|
|
else if (TREE_CODE (decl) == TYPE_DECL
|
|
|
|
|
&& TREE_CODE (type) == UNION_TYPE
|
|
|
|
|
&& TYPE_MODE (type) == DECL_MODE (TYPE_FIELDS (type)))
|
|
|
|
|
TYPE_TRANSPARENT_UNION (type) = 1;
|
|
|
|
|
else
|
|
|
|
|
warning_with_decl (decl, "`transparent_union' attribute ignored");
|
|
|
|
|
}
|
1994-08-02 20:15:59 +00:00
|
|
|
|
else if (TREE_CODE (name) != TREE_LIST)
|
|
|
|
|
{
|
|
|
|
|
#ifdef VALID_MACHINE_ATTRIBUTE
|
|
|
|
|
if (VALID_MACHINE_ATTRIBUTE (type, new_attr, name))
|
1995-05-30 05:05:38 +00:00
|
|
|
|
{
|
1994-08-02 20:15:59 +00:00
|
|
|
|
register tree atlist;
|
|
|
|
|
|
|
|
|
|
for (atlist = new_attr; atlist; atlist = TREE_CHAIN (atlist))
|
|
|
|
|
if (TREE_VALUE (atlist) == name)
|
|
|
|
|
goto found_attr;
|
|
|
|
|
|
|
|
|
|
new_attr = tree_cons (NULL_TREE, name, new_attr);
|
|
|
|
|
found_attr:;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
#endif
|
|
|
|
|
warning ("`%s' attribute directive ignored",
|
|
|
|
|
IDENTIFIER_POINTER (name));
|
|
|
|
|
}
|
|
|
|
|
else if ( args = TREE_CHAIN(name),
|
1994-11-15 04:52:19 +00:00
|
|
|
|
(!strcmp (IDENTIFIER_POINTER (name = TREE_PURPOSE (name)), "mode")
|
|
|
|
|
|| !strcmp (IDENTIFIER_POINTER (name), "__mode__"))
|
1994-08-02 20:15:59 +00:00
|
|
|
|
&& list_length (args) == 1
|
|
|
|
|
&& TREE_CODE (TREE_VALUE (args)) == IDENTIFIER_NODE)
|
|
|
|
|
{
|
|
|
|
|
int i;
|
|
|
|
|
char *specified_name
|
|
|
|
|
= IDENTIFIER_POINTER (TREE_VALUE (args));
|
|
|
|
|
|
|
|
|
|
/* Give this decl a type with the specified mode. */
|
|
|
|
|
for (i = 0; i < NUM_MACHINE_MODES; i++)
|
|
|
|
|
if (!strcmp (specified_name, GET_MODE_NAME (i)))
|
|
|
|
|
{
|
|
|
|
|
tree typefm
|
|
|
|
|
= type_for_mode (i, TREE_UNSIGNED (type));
|
|
|
|
|
if (typefm != 0)
|
|
|
|
|
{
|
|
|
|
|
TREE_TYPE (decl) = type = typefm;
|
|
|
|
|
DECL_SIZE (decl) = 0;
|
|
|
|
|
layout_decl (decl, 0);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
error ("no data type for mode `%s'", specified_name);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
if (i == NUM_MACHINE_MODES)
|
|
|
|
|
error_with_decl (decl, "unknown machine mode `%s'", specified_name);
|
|
|
|
|
}
|
1994-11-15 04:52:19 +00:00
|
|
|
|
else if ((!strcmp (IDENTIFIER_POINTER (name), "section")
|
|
|
|
|
|| !strcmp (IDENTIFIER_POINTER (name), "__section__"))
|
1994-08-02 20:15:59 +00:00
|
|
|
|
&& list_length (args) == 1
|
|
|
|
|
&& TREE_CODE (TREE_VALUE (args)) == STRING_CST)
|
|
|
|
|
{
|
|
|
|
|
#ifdef ASM_OUTPUT_SECTION_NAME
|
|
|
|
|
if (TREE_CODE (decl) == FUNCTION_DECL || TREE_CODE (decl) == VAR_DECL)
|
|
|
|
|
{
|
|
|
|
|
if (TREE_CODE (decl) == VAR_DECL && current_function_decl != NULL_TREE)
|
|
|
|
|
error_with_decl (decl,
|
|
|
|
|
"section attribute cannot be specified for local variables");
|
|
|
|
|
/* The decl may have already been given a section attribute from
|
|
|
|
|
a previous declaration. Ensure they match. */
|
|
|
|
|
else if (DECL_SECTION_NAME (decl) != NULL_TREE
|
|
|
|
|
&& strcmp (TREE_STRING_POINTER (DECL_SECTION_NAME (decl)),
|
|
|
|
|
TREE_STRING_POINTER (TREE_VALUE (args))) != 0)
|
|
|
|
|
error_with_decl (decl,
|
|
|
|
|
"section of `%s' conflicts with previous declaration");
|
|
|
|
|
else
|
|
|
|
|
DECL_SECTION_NAME (decl) = TREE_VALUE (args);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
error_with_decl (decl,
|
|
|
|
|
"section attribute not allowed for `%s'");
|
|
|
|
|
#else
|
|
|
|
|
error_with_decl (decl, "section attributes are not supported for this target");
|
|
|
|
|
#endif
|
|
|
|
|
}
|
1994-11-15 04:52:19 +00:00
|
|
|
|
else if ((!strcmp (IDENTIFIER_POINTER (name), "aligned")
|
|
|
|
|
|| !strcmp (IDENTIFIER_POINTER (name), "__aligned__"))
|
1994-08-02 20:15:59 +00:00
|
|
|
|
&& list_length (args) == 1
|
|
|
|
|
&& TREE_CODE (TREE_VALUE (args)) == INTEGER_CST)
|
|
|
|
|
{
|
|
|
|
|
tree align_expr = TREE_VALUE (args);
|
|
|
|
|
int align;
|
|
|
|
|
|
|
|
|
|
/* 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_with_decl (decl,
|
|
|
|
|
"requested alignment of `%s' is not a constant");
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
align = TREE_INT_CST_LOW (align_expr) * BITS_PER_UNIT;
|
1995-05-30 05:05:38 +00:00
|
|
|
|
|
1994-08-02 20:15:59 +00:00
|
|
|
|
if (exact_log2 (align) == -1)
|
|
|
|
|
error_with_decl (decl,
|
|
|
|
|
"requested alignment of `%s' is not a power of 2");
|
|
|
|
|
else if (TREE_CODE (decl) != VAR_DECL
|
|
|
|
|
&& TREE_CODE (decl) != FIELD_DECL)
|
|
|
|
|
error_with_decl (decl,
|
|
|
|
|
"alignment specified for `%s'");
|
|
|
|
|
else
|
|
|
|
|
DECL_ALIGN (decl) = align;
|
|
|
|
|
}
|
1994-11-15 04:52:19 +00:00
|
|
|
|
else if ((!strcmp (IDENTIFIER_POINTER (name), "format")
|
|
|
|
|
|| !strcmp (IDENTIFIER_POINTER (name), "__format__"))
|
1994-08-02 20:15:59 +00:00
|
|
|
|
&& list_length (args) == 3
|
|
|
|
|
&& TREE_CODE (TREE_VALUE (args)) == IDENTIFIER_NODE
|
|
|
|
|
&& TREE_CODE (TREE_VALUE (TREE_CHAIN (args))) == INTEGER_CST
|
|
|
|
|
&& TREE_CODE (TREE_VALUE (TREE_CHAIN (TREE_CHAIN (args)))) == INTEGER_CST )
|
|
|
|
|
{
|
|
|
|
|
tree format_type = TREE_VALUE (args);
|
|
|
|
|
tree format_num_expr = TREE_VALUE (TREE_CHAIN (args));
|
|
|
|
|
tree first_arg_num_expr = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (args)));
|
|
|
|
|
int format_num;
|
|
|
|
|
int first_arg_num;
|
|
|
|
|
int is_scan;
|
|
|
|
|
tree argument;
|
|
|
|
|
int arg_num;
|
1995-05-30 05:05:38 +00:00
|
|
|
|
|
1994-08-02 20:15:59 +00:00
|
|
|
|
if (TREE_CODE (decl) != FUNCTION_DECL)
|
|
|
|
|
{
|
|
|
|
|
error_with_decl (decl,
|
|
|
|
|
"argument format specified for non-function `%s'");
|
|
|
|
|
continue;
|
|
|
|
|
}
|
1995-05-30 05:05:38 +00:00
|
|
|
|
|
1994-11-15 04:52:19 +00:00
|
|
|
|
if (!strcmp (IDENTIFIER_POINTER (format_type), "printf")
|
|
|
|
|
|| !strcmp (IDENTIFIER_POINTER (format_type), "__printf__"))
|
1994-08-02 20:15:59 +00:00
|
|
|
|
is_scan = 0;
|
1994-11-15 04:52:19 +00:00
|
|
|
|
else if (!strcmp (IDENTIFIER_POINTER (format_type), "scanf")
|
|
|
|
|
|| !strcmp (IDENTIFIER_POINTER (format_type), "__scanf__"))
|
1994-08-02 20:15:59 +00:00
|
|
|
|
is_scan = 1;
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
error_with_decl (decl, "unrecognized format specifier for `%s'");
|
|
|
|
|
continue;
|
|
|
|
|
}
|
1995-05-30 05:05:38 +00:00
|
|
|
|
|
1994-08-02 20:15:59 +00:00
|
|
|
|
/* Strip any conversions from the string index and first arg number
|
|
|
|
|
and verify they are constants. */
|
|
|
|
|
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);
|
|
|
|
|
|
|
|
|
|
while (TREE_CODE (first_arg_num_expr) == NOP_EXPR
|
|
|
|
|
|| TREE_CODE (first_arg_num_expr) == CONVERT_EXPR
|
|
|
|
|
|| TREE_CODE (first_arg_num_expr) == NON_LVALUE_EXPR)
|
|
|
|
|
first_arg_num_expr = TREE_OPERAND (first_arg_num_expr, 0);
|
|
|
|
|
|
|
|
|
|
if (TREE_CODE (format_num_expr) != INTEGER_CST
|
|
|
|
|
|| TREE_CODE (first_arg_num_expr) != INTEGER_CST)
|
|
|
|
|
{
|
|
|
|
|
error_with_decl (decl,
|
|
|
|
|
"format string for `%s' has non-constant operand number");
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
format_num = TREE_INT_CST_LOW (format_num_expr);
|
|
|
|
|
first_arg_num = TREE_INT_CST_LOW (first_arg_num_expr);
|
|
|
|
|
if (first_arg_num != 0 && first_arg_num <= format_num)
|
|
|
|
|
{
|
|
|
|
|
error_with_decl (decl,
|
|
|
|
|
"format string arg follows the args to be formatted, for `%s'");
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* If a parameter list is specified, verify that the format_num
|
|
|
|
|
argument is actually a string, in case the format attribute
|
|
|
|
|
is in error. */
|
|
|
|
|
argument = TYPE_ARG_TYPES (type);
|
|
|
|
|
if (argument)
|
|
|
|
|
{
|
|
|
|
|
for (arg_num = 1; ; ++arg_num)
|
|
|
|
|
{
|
|
|
|
|
if (argument == 0 || arg_num == format_num)
|
|
|
|
|
break;
|
|
|
|
|
argument = TREE_CHAIN (argument);
|
|
|
|
|
}
|
|
|
|
|
if (! argument
|
|
|
|
|
|| TREE_CODE (TREE_VALUE (argument)) != POINTER_TYPE
|
|
|
|
|
|| (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_VALUE (argument)))
|
|
|
|
|
!= char_type_node))
|
|
|
|
|
{
|
|
|
|
|
error_with_decl (decl,
|
|
|
|
|
"format string arg not a string type, for `%s'");
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
if (first_arg_num != 0)
|
|
|
|
|
{
|
|
|
|
|
/* Verify that first_arg_num points to the last arg, the ... */
|
|
|
|
|
while (argument)
|
|
|
|
|
arg_num++, argument = TREE_CHAIN (argument);
|
|
|
|
|
if (arg_num != first_arg_num)
|
|
|
|
|
{
|
|
|
|
|
error_with_decl (decl,
|
|
|
|
|
"args to be formatted is not ..., for `%s'");
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
record_function_format (DECL_NAME (decl), DECL_ASSEMBLER_NAME (decl),
|
|
|
|
|
is_scan, format_num, first_arg_num);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
warning ("`%s' attribute directive ignored",
|
|
|
|
|
IDENTIFIER_POINTER (name));
|
|
|
|
|
|
|
|
|
|
TREE_TYPE (decl) = build_type_attribute_variant (type, new_attr);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Check a printf/fprintf/sprintf/scanf/fscanf/sscanf format against
|
|
|
|
|
a parameter list. */
|
|
|
|
|
|
|
|
|
|
#define T_I &integer_type_node
|
|
|
|
|
#define T_L &long_integer_type_node
|
1994-09-18 21:25:02 +00:00
|
|
|
|
#define T_LL &long_long_integer_type_node
|
1994-08-02 20:15:59 +00:00
|
|
|
|
#define T_S &short_integer_type_node
|
|
|
|
|
#define T_UI &unsigned_type_node
|
|
|
|
|
#define T_UL &long_unsigned_type_node
|
1994-09-18 21:25:02 +00:00
|
|
|
|
#define T_ULL &long_long_unsigned_type_node
|
1994-08-02 20:15:59 +00:00
|
|
|
|
#define T_US &short_unsigned_type_node
|
|
|
|
|
#define T_F &float_type_node
|
|
|
|
|
#define T_D &double_type_node
|
|
|
|
|
#define T_LD &long_double_type_node
|
|
|
|
|
#define T_C &char_type_node
|
|
|
|
|
#define T_V &void_type_node
|
|
|
|
|
#define T_W &wchar_type_node
|
|
|
|
|
#define T_ST &sizetype
|
|
|
|
|
|
|
|
|
|
typedef struct {
|
|
|
|
|
char *format_chars;
|
|
|
|
|
int pointer_count;
|
|
|
|
|
/* Type of argument if no length modifier is used. */
|
|
|
|
|
tree *nolen;
|
|
|
|
|
/* Type of argument if length modifier for shortening is used.
|
|
|
|
|
If NULL, then this modifier is not allowed. */
|
|
|
|
|
tree *hlen;
|
|
|
|
|
/* Type of argument if length modifier `l' is used.
|
|
|
|
|
If NULL, then this modifier is not allowed. */
|
|
|
|
|
tree *llen;
|
1994-11-15 04:52:19 +00:00
|
|
|
|
/* Type of argument if length modifier `q' or `ll' is used.
|
1994-09-18 21:25:02 +00:00
|
|
|
|
If NULL, then this modifier is not allowed. */
|
|
|
|
|
tree *qlen;
|
1994-08-02 20:15:59 +00:00
|
|
|
|
/* Type of argument if length modifier `L' is used.
|
|
|
|
|
If NULL, then this modifier is not allowed. */
|
|
|
|
|
tree *bigllen;
|
|
|
|
|
/* List of other modifier characters allowed with these options. */
|
|
|
|
|
char *flag_chars;
|
|
|
|
|
} format_char_info;
|
|
|
|
|
|
|
|
|
|
static format_char_info print_char_table[] = {
|
1994-11-15 04:52:19 +00:00
|
|
|
|
{ "di", 0, T_I, T_I, T_L, T_LL, T_LL, "-wp0 +" },
|
|
|
|
|
{ "oxX", 0, T_UI, T_UI, T_UL, T_ULL, T_ULL, "-wp0#" },
|
1995-03-11 03:51:44 +00:00
|
|
|
|
{ "u", 0, T_UI, T_UI, T_UL, T_ULL, T_ULL, "-wp0" },
|
1994-08-02 20:15:59 +00:00
|
|
|
|
/* Two GNU extensions. */
|
1994-09-18 21:25:02 +00:00
|
|
|
|
{ "Z", 0, T_ST, NULL, NULL, NULL, NULL, "-wp0" },
|
|
|
|
|
{ "m", 0, T_UI, T_UI, T_UL, NULL, NULL, "-wp" },
|
|
|
|
|
{ "feEgG", 0, T_D, NULL, NULL, NULL, T_LD, "-wp0 +#" },
|
|
|
|
|
{ "c", 0, T_I, NULL, T_W, NULL, NULL, "-w" },
|
|
|
|
|
{ "C", 0, T_W, NULL, NULL, NULL, NULL, "-w" },
|
|
|
|
|
{ "s", 1, T_C, NULL, T_W, NULL, NULL, "-wp" },
|
|
|
|
|
{ "S", 1, T_W, NULL, NULL, NULL, NULL, "-wp" },
|
|
|
|
|
{ "p", 1, T_V, NULL, NULL, NULL, NULL, "-w" },
|
----------------------------------
GCC-2.6.1 COMES TO FREEBSD-current
----------------------------------
Everybody needs to 'make world'.
Oakland, Nov 2nd 1994. In a surprise move this sunny afternoon, the release-
engineer for the slightly delayed FreeBSD-2.0, Poul-Henning Kamp (28),
decided to pull in the new version 2.6.1 of the GNU C-compiler.
The new version of the compiler was release today at noon, and hardly 9
hours later it was committed into the FreeBSD-current source-repository.
"It's is simply because we have had too much trouble with the version 2.6.0
of the compiler" Poul-Henning told the FreeBSD-Gazette, "we took a gamble
when we decided to use that as our compiler for the 2.0 release, but it
seems to pay of in the end now" he concludes.
The move has not been discussed on the "core" list at all, and will come as
a surprise for most Poul-Hennings peers. "I have only discussed it with
Jordan [J. K. Hubbard, the FreeBSD's resident humourist], and we agreed that
we needed to do it, so ... I did it!". After a breath he added with a grin:
"My email will probably get an all time 'disk-full' now!".
This will bring quite a flag-day to the FreeBSD developers, the patch-file
is almost 1.4 Megabyte, and they will have to run "make world" to get
entirely -current again. "Too bad, but we just had to do this." Was
the only comment from Poul-Henning to these problems.
When asked how this move would impact the 2.0 release-date, Poul-Hennings
face grew dark, he mumbled some very Danish words while he moved his fingers
in strange geometrical patterns. Immediately something ecclipsed the Sun, a
minor tremor shook the buildings, and the temperature fell significantly.
We decided not to pursure the question.
-----------
JOB-SECTION
-----------
Are you a dedicated GCC-hacker ?
We BADLY need somebody to look at the 'freebsd' OS in gcc, sanitize it and
carry the patches back to the GNU people. In particular, we need to get
out of the "i386-only" spot we are in now. I have the stuff to take a
gnu-dist into bmake-form, and will do that part.
Please apply to phk@freebsd.org
No Novice Need Apply.
1994-11-03 06:52:42 +00:00
|
|
|
|
{ "n", 1, T_I, T_S, T_L, T_LL, NULL, "" },
|
1994-08-02 20:15:59 +00:00
|
|
|
|
{ NULL }
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static format_char_info scan_char_table[] = {
|
1994-11-15 04:52:19 +00:00
|
|
|
|
{ "di", 1, T_I, T_S, T_L, T_LL, T_LL, "*" },
|
1995-05-30 05:05:38 +00:00
|
|
|
|
{ "ouxX", 1, T_UI, T_US, T_UL, T_ULL, T_ULL, "*" },
|
1994-09-18 21:25:02 +00:00
|
|
|
|
{ "efgEG", 1, T_F, NULL, T_D, NULL, T_LD, "*" },
|
|
|
|
|
{ "sc", 1, T_C, NULL, T_W, NULL, NULL, "*a" },
|
|
|
|
|
{ "[", 1, T_C, NULL, NULL, NULL, NULL, "*a" },
|
|
|
|
|
{ "C", 1, T_W, NULL, NULL, NULL, NULL, "*" },
|
|
|
|
|
{ "S", 1, T_W, NULL, NULL, NULL, NULL, "*" },
|
|
|
|
|
{ "p", 2, T_V, NULL, NULL, NULL, NULL, "*" },
|
----------------------------------
GCC-2.6.1 COMES TO FREEBSD-current
----------------------------------
Everybody needs to 'make world'.
Oakland, Nov 2nd 1994. In a surprise move this sunny afternoon, the release-
engineer for the slightly delayed FreeBSD-2.0, Poul-Henning Kamp (28),
decided to pull in the new version 2.6.1 of the GNU C-compiler.
The new version of the compiler was release today at noon, and hardly 9
hours later it was committed into the FreeBSD-current source-repository.
"It's is simply because we have had too much trouble with the version 2.6.0
of the compiler" Poul-Henning told the FreeBSD-Gazette, "we took a gamble
when we decided to use that as our compiler for the 2.0 release, but it
seems to pay of in the end now" he concludes.
The move has not been discussed on the "core" list at all, and will come as
a surprise for most Poul-Hennings peers. "I have only discussed it with
Jordan [J. K. Hubbard, the FreeBSD's resident humourist], and we agreed that
we needed to do it, so ... I did it!". After a breath he added with a grin:
"My email will probably get an all time 'disk-full' now!".
This will bring quite a flag-day to the FreeBSD developers, the patch-file
is almost 1.4 Megabyte, and they will have to run "make world" to get
entirely -current again. "Too bad, but we just had to do this." Was
the only comment from Poul-Henning to these problems.
When asked how this move would impact the 2.0 release-date, Poul-Hennings
face grew dark, he mumbled some very Danish words while he moved his fingers
in strange geometrical patterns. Immediately something ecclipsed the Sun, a
minor tremor shook the buildings, and the temperature fell significantly.
We decided not to pursure the question.
-----------
JOB-SECTION
-----------
Are you a dedicated GCC-hacker ?
We BADLY need somebody to look at the 'freebsd' OS in gcc, sanitize it and
carry the patches back to the GNU people. In particular, we need to get
out of the "i386-only" spot we are in now. I have the stuff to take a
gnu-dist into bmake-form, and will do that part.
Please apply to phk@freebsd.org
No Novice Need Apply.
1994-11-03 06:52:42 +00:00
|
|
|
|
{ "n", 1, T_I, T_S, T_L, T_LL, NULL, "" },
|
1994-08-02 20:15:59 +00:00
|
|
|
|
{ NULL }
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
typedef struct function_format_info {
|
|
|
|
|
struct function_format_info *next; /* next structure on the list */
|
|
|
|
|
tree name; /* identifier such as "printf" */
|
|
|
|
|
tree assembler_name; /* optional mangled identifier (for C++) */
|
|
|
|
|
int is_scan; /* TRUE if *scanf */
|
|
|
|
|
int format_num; /* number of format argument */
|
|
|
|
|
int first_arg_num; /* number of first arg (zero for varargs) */
|
|
|
|
|
} function_format_info;
|
|
|
|
|
|
|
|
|
|
static function_format_info *function_format_list = NULL;
|
|
|
|
|
|
|
|
|
|
static void check_format_info PROTO((function_format_info *, tree));
|
|
|
|
|
|
|
|
|
|
/* Initialize the table of functions to perform format checking on.
|
|
|
|
|
The ANSI functions are always checked (whether <stdio.h> is
|
|
|
|
|
included or not), since it is common to call printf without
|
|
|
|
|
including <stdio.h>. There shouldn't be a problem with this,
|
|
|
|
|
since ANSI reserves these function names whether you include the
|
|
|
|
|
header file or not. In any case, the checking is harmless. */
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
init_function_format_info ()
|
|
|
|
|
{
|
|
|
|
|
record_function_format (get_identifier ("printf"), NULL_TREE, 0, 1, 2);
|
|
|
|
|
record_function_format (get_identifier ("fprintf"), NULL_TREE, 0, 2, 3);
|
|
|
|
|
record_function_format (get_identifier ("sprintf"), NULL_TREE, 0, 2, 3);
|
|
|
|
|
record_function_format (get_identifier ("scanf"), NULL_TREE, 1, 1, 2);
|
|
|
|
|
record_function_format (get_identifier ("fscanf"), NULL_TREE, 1, 2, 3);
|
|
|
|
|
record_function_format (get_identifier ("sscanf"), NULL_TREE, 1, 2, 3);
|
|
|
|
|
record_function_format (get_identifier ("vprintf"), NULL_TREE, 0, 1, 0);
|
|
|
|
|
record_function_format (get_identifier ("vfprintf"), NULL_TREE, 0, 2, 0);
|
|
|
|
|
record_function_format (get_identifier ("vsprintf"), NULL_TREE, 0, 2, 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Record information for argument format checking. FUNCTION_IDENT is
|
|
|
|
|
the identifier node for the name of the function to check (its decl
|
|
|
|
|
need not exist yet). IS_SCAN is true for scanf-type format checking;
|
|
|
|
|
false indicates printf-style format checking. FORMAT_NUM is the number
|
|
|
|
|
of the argument which is the format control string (starting from 1).
|
|
|
|
|
FIRST_ARG_NUM is the number of the first actual argument to check
|
|
|
|
|
against teh format string, or zero if no checking is not be done
|
|
|
|
|
(e.g. for varargs such as vfprintf). */
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
record_function_format (name, assembler_name, is_scan,
|
|
|
|
|
format_num, first_arg_num)
|
|
|
|
|
tree name;
|
|
|
|
|
tree assembler_name;
|
|
|
|
|
int is_scan;
|
|
|
|
|
int format_num;
|
|
|
|
|
int first_arg_num;
|
|
|
|
|
{
|
|
|
|
|
function_format_info *info;
|
|
|
|
|
|
|
|
|
|
/* Re-use existing structure if it's there. */
|
|
|
|
|
|
|
|
|
|
for (info = function_format_list; info; info = info->next)
|
|
|
|
|
{
|
|
|
|
|
if (info->name == name && info->assembler_name == assembler_name)
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
if (! info)
|
|
|
|
|
{
|
|
|
|
|
info = (function_format_info *) xmalloc (sizeof (function_format_info));
|
|
|
|
|
info->next = function_format_list;
|
|
|
|
|
function_format_list = info;
|
|
|
|
|
|
|
|
|
|
info->name = name;
|
|
|
|
|
info->assembler_name = assembler_name;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
info->is_scan = is_scan;
|
|
|
|
|
info->format_num = format_num;
|
|
|
|
|
info->first_arg_num = first_arg_num;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static char tfaff[] = "too few arguments for format";
|
|
|
|
|
|
|
|
|
|
/* Check the argument list of a call to printf, scanf, etc.
|
|
|
|
|
NAME is the function identifier.
|
|
|
|
|
ASSEMBLER_NAME is the function's assembler identifier.
|
|
|
|
|
(Either NAME or ASSEMBLER_NAME, but not both, may be NULL_TREE.)
|
|
|
|
|
PARAMS is the list of argument values. */
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
check_function_format (name, assembler_name, params)
|
|
|
|
|
tree name;
|
|
|
|
|
tree assembler_name;
|
|
|
|
|
tree params;
|
|
|
|
|
{
|
|
|
|
|
function_format_info *info;
|
|
|
|
|
|
|
|
|
|
/* See if this function is a format function. */
|
|
|
|
|
for (info = function_format_list; info; info = info->next)
|
|
|
|
|
{
|
|
|
|
|
if (info->assembler_name
|
|
|
|
|
? (info->assembler_name == assembler_name)
|
|
|
|
|
: (info->name == name))
|
|
|
|
|
{
|
|
|
|
|
/* Yup; check it. */
|
|
|
|
|
check_format_info (info, params);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Check the argument list of a call to printf, scanf, etc.
|
|
|
|
|
INFO points to the function_format_info structure.
|
|
|
|
|
PARAMS is the list of argument values. */
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
check_format_info (info, params)
|
|
|
|
|
function_format_info *info;
|
|
|
|
|
tree params;
|
|
|
|
|
{
|
|
|
|
|
int i;
|
|
|
|
|
int arg_num;
|
|
|
|
|
int suppressed, wide, precise;
|
|
|
|
|
int length_char;
|
|
|
|
|
int format_char;
|
|
|
|
|
int format_length;
|
|
|
|
|
tree format_tree;
|
|
|
|
|
tree cur_param;
|
|
|
|
|
tree cur_type;
|
|
|
|
|
tree wanted_type;
|
|
|
|
|
tree first_fillin_param;
|
|
|
|
|
char *format_chars;
|
|
|
|
|
format_char_info *fci;
|
|
|
|
|
static char message[132];
|
|
|
|
|
char flag_chars[8];
|
|
|
|
|
int has_operand_number = 0;
|
|
|
|
|
|
|
|
|
|
/* Skip to format argument. If the argument isn't available, there's
|
|
|
|
|
no work for us to do; prototype checking will catch the problem. */
|
|
|
|
|
for (arg_num = 1; ; ++arg_num)
|
|
|
|
|
{
|
|
|
|
|
if (params == 0)
|
|
|
|
|
return;
|
|
|
|
|
if (arg_num == info->format_num)
|
|
|
|
|
break;
|
|
|
|
|
params = TREE_CHAIN (params);
|
|
|
|
|
}
|
|
|
|
|
format_tree = TREE_VALUE (params);
|
|
|
|
|
params = TREE_CHAIN (params);
|
|
|
|
|
if (format_tree == 0)
|
|
|
|
|
return;
|
|
|
|
|
/* We can only check the format if it's a string constant. */
|
|
|
|
|
while (TREE_CODE (format_tree) == NOP_EXPR)
|
|
|
|
|
format_tree = TREE_OPERAND (format_tree, 0); /* strip coercion */
|
|
|
|
|
if (format_tree == null_pointer_node)
|
|
|
|
|
{
|
|
|
|
|
warning ("null format string");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (TREE_CODE (format_tree) != ADDR_EXPR)
|
|
|
|
|
return;
|
|
|
|
|
format_tree = TREE_OPERAND (format_tree, 0);
|
|
|
|
|
if (TREE_CODE (format_tree) != STRING_CST)
|
|
|
|
|
return;
|
|
|
|
|
format_chars = TREE_STRING_POINTER (format_tree);
|
|
|
|
|
format_length = TREE_STRING_LENGTH (format_tree);
|
|
|
|
|
if (format_length <= 1)
|
|
|
|
|
warning ("zero-length format string");
|
|
|
|
|
if (format_chars[--format_length] != 0)
|
|
|
|
|
{
|
|
|
|
|
warning ("unterminated format string");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
/* Skip to first argument to check. */
|
|
|
|
|
while (arg_num + 1 < info->first_arg_num)
|
|
|
|
|
{
|
|
|
|
|
if (params == 0)
|
|
|
|
|
return;
|
|
|
|
|
params = TREE_CHAIN (params);
|
|
|
|
|
++arg_num;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
first_fillin_param = params;
|
|
|
|
|
while (1)
|
|
|
|
|
{
|
|
|
|
|
int aflag;
|
|
|
|
|
if (*format_chars == 0)
|
|
|
|
|
{
|
|
|
|
|
if (format_chars - TREE_STRING_POINTER (format_tree) != format_length)
|
|
|
|
|
warning ("embedded `\\0' in format");
|
|
|
|
|
if (info->first_arg_num != 0 && params != 0 && ! has_operand_number)
|
|
|
|
|
warning ("too many arguments for format");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (*format_chars++ != '%')
|
|
|
|
|
continue;
|
|
|
|
|
if (*format_chars == 0)
|
|
|
|
|
{
|
|
|
|
|
warning ("spurious trailing `%%' in format");
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
if (*format_chars == '%')
|
|
|
|
|
{
|
|
|
|
|
++format_chars;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
flag_chars[0] = 0;
|
|
|
|
|
suppressed = wide = precise = FALSE;
|
|
|
|
|
if (info->is_scan)
|
|
|
|
|
{
|
|
|
|
|
suppressed = *format_chars == '*';
|
|
|
|
|
if (suppressed)
|
|
|
|
|
++format_chars;
|
|
|
|
|
while (isdigit (*format_chars))
|
|
|
|
|
++format_chars;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
/* See if we have a number followed by a dollar sign. If we do,
|
|
|
|
|
it is an operand number, so set PARAMS to that operand. */
|
|
|
|
|
if (*format_chars >= '0' && *format_chars <= '9')
|
|
|
|
|
{
|
|
|
|
|
char *p = format_chars;
|
|
|
|
|
|
|
|
|
|
while (*p >= '0' && *p++ <= '9')
|
|
|
|
|
;
|
|
|
|
|
|
|
|
|
|
if (*p == '$')
|
|
|
|
|
{
|
|
|
|
|
int opnum = atoi (format_chars);
|
|
|
|
|
|
|
|
|
|
params = first_fillin_param;
|
|
|
|
|
format_chars = p + 1;
|
|
|
|
|
has_operand_number = 1;
|
|
|
|
|
|
|
|
|
|
for (i = 1; i < opnum && params != 0; i++)
|
|
|
|
|
params = TREE_CHAIN (params);
|
|
|
|
|
|
|
|
|
|
if (opnum == 0 || params == 0)
|
|
|
|
|
{
|
|
|
|
|
warning ("operand number out of range in format");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
while (*format_chars != 0 && index (" +#0-", *format_chars) != 0)
|
|
|
|
|
{
|
|
|
|
|
if (index (flag_chars, *format_chars) != 0)
|
|
|
|
|
{
|
|
|
|
|
sprintf (message, "repeated `%c' flag in format",
|
|
|
|
|
*format_chars);
|
|
|
|
|
warning (message);
|
|
|
|
|
}
|
|
|
|
|
i = strlen (flag_chars);
|
|
|
|
|
flag_chars[i++] = *format_chars++;
|
|
|
|
|
flag_chars[i] = 0;
|
|
|
|
|
}
|
1995-05-30 05:05:38 +00:00
|
|
|
|
/* "If the space and + flags both appear,
|
1994-08-02 20:15:59 +00:00
|
|
|
|
the space flag will be ignored." */
|
|
|
|
|
if (index (flag_chars, ' ') != 0
|
|
|
|
|
&& index (flag_chars, '+') != 0)
|
|
|
|
|
warning ("use of both ` ' and `+' flags in format");
|
|
|
|
|
/* "If the 0 and - flags both appear,
|
|
|
|
|
the 0 flag will be ignored." */
|
|
|
|
|
if (index (flag_chars, '0') != 0
|
|
|
|
|
&& index (flag_chars, '-') != 0)
|
|
|
|
|
warning ("use of both `0' and `-' flags in format");
|
|
|
|
|
if (*format_chars == '*')
|
|
|
|
|
{
|
|
|
|
|
wide = TRUE;
|
|
|
|
|
/* "...a field width...may be indicated by an asterisk.
|
|
|
|
|
In this case, an int argument supplies the field width..." */
|
|
|
|
|
++format_chars;
|
|
|
|
|
if (params == 0)
|
|
|
|
|
{
|
|
|
|
|
warning (tfaff);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (info->first_arg_num != 0)
|
|
|
|
|
{
|
|
|
|
|
cur_param = TREE_VALUE (params);
|
|
|
|
|
params = TREE_CHAIN (params);
|
|
|
|
|
++arg_num;
|
|
|
|
|
/* size_t is generally not valid here.
|
|
|
|
|
It will work on most machines, because size_t and int
|
|
|
|
|
have the same mode. But might as well warn anyway,
|
|
|
|
|
since it will fail on other machines. */
|
|
|
|
|
if ((TYPE_MAIN_VARIANT (TREE_TYPE (cur_param))
|
|
|
|
|
!= integer_type_node)
|
|
|
|
|
&&
|
|
|
|
|
(TYPE_MAIN_VARIANT (TREE_TYPE (cur_param))
|
|
|
|
|
!= unsigned_type_node))
|
|
|
|
|
{
|
|
|
|
|
sprintf (message,
|
|
|
|
|
"field width is not type int (arg %d)",
|
|
|
|
|
arg_num);
|
|
|
|
|
warning (message);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
while (isdigit (*format_chars))
|
|
|
|
|
{
|
|
|
|
|
wide = TRUE;
|
|
|
|
|
++format_chars;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (*format_chars == '.')
|
|
|
|
|
{
|
|
|
|
|
precise = TRUE;
|
|
|
|
|
++format_chars;
|
|
|
|
|
if (*format_chars != '*' && !isdigit (*format_chars))
|
|
|
|
|
warning ("`.' not followed by `*' or digit in format");
|
|
|
|
|
/* "...a...precision...may be indicated by an asterisk.
|
|
|
|
|
In this case, an int argument supplies the...precision." */
|
|
|
|
|
if (*format_chars == '*')
|
|
|
|
|
{
|
|
|
|
|
if (info->first_arg_num != 0)
|
|
|
|
|
{
|
|
|
|
|
++format_chars;
|
|
|
|
|
if (params == 0)
|
|
|
|
|
{
|
|
|
|
|
warning (tfaff);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
cur_param = TREE_VALUE (params);
|
|
|
|
|
params = TREE_CHAIN (params);
|
|
|
|
|
++arg_num;
|
|
|
|
|
if (TYPE_MAIN_VARIANT (TREE_TYPE (cur_param))
|
|
|
|
|
!= integer_type_node)
|
|
|
|
|
{
|
|
|
|
|
sprintf (message,
|
|
|
|
|
"field width is not type int (arg %d)",
|
|
|
|
|
arg_num);
|
|
|
|
|
warning (message);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
while (isdigit (*format_chars))
|
|
|
|
|
++format_chars;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
1994-09-18 21:25:02 +00:00
|
|
|
|
if (*format_chars == 'h' || *format_chars == 'l' || *format_chars == 'q' ||
|
|
|
|
|
*format_chars == 'L')
|
1994-08-02 20:15:59 +00:00
|
|
|
|
length_char = *format_chars++;
|
|
|
|
|
else
|
|
|
|
|
length_char = 0;
|
1994-11-15 04:52:19 +00:00
|
|
|
|
if (length_char == 'l' && *format_chars == 'l')
|
|
|
|
|
length_char = 'q', format_chars++;
|
1994-08-02 20:15:59 +00:00
|
|
|
|
aflag = 0;
|
|
|
|
|
if (*format_chars == 'a')
|
|
|
|
|
{
|
|
|
|
|
aflag = 1;
|
|
|
|
|
format_chars++;
|
|
|
|
|
}
|
|
|
|
|
if (suppressed && length_char != 0)
|
|
|
|
|
{
|
|
|
|
|
sprintf (message,
|
|
|
|
|
"use of `*' and `%c' together in format",
|
|
|
|
|
length_char);
|
|
|
|
|
warning (message);
|
|
|
|
|
}
|
|
|
|
|
format_char = *format_chars;
|
|
|
|
|
if (format_char == 0)
|
|
|
|
|
{
|
|
|
|
|
warning ("conversion lacks type at end of format");
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
format_chars++;
|
|
|
|
|
fci = info->is_scan ? scan_char_table : print_char_table;
|
|
|
|
|
while (fci->format_chars != 0
|
|
|
|
|
&& index (fci->format_chars, format_char) == 0)
|
|
|
|
|
++fci;
|
|
|
|
|
if (fci->format_chars == 0)
|
|
|
|
|
{
|
|
|
|
|
if (format_char >= 040 && format_char < 0177)
|
|
|
|
|
sprintf (message,
|
|
|
|
|
"unknown conversion type character `%c' in format",
|
|
|
|
|
format_char);
|
|
|
|
|
else
|
|
|
|
|
sprintf (message,
|
|
|
|
|
"unknown conversion type character 0x%x in format",
|
|
|
|
|
format_char);
|
|
|
|
|
warning (message);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
if (wide && index (fci->flag_chars, 'w') == 0)
|
|
|
|
|
{
|
|
|
|
|
sprintf (message, "width used with `%c' format",
|
|
|
|
|
format_char);
|
|
|
|
|
warning (message);
|
|
|
|
|
}
|
|
|
|
|
if (precise && index (fci->flag_chars, 'p') == 0)
|
|
|
|
|
{
|
|
|
|
|
sprintf (message, "precision used with `%c' format",
|
|
|
|
|
format_char);
|
|
|
|
|
warning (message);
|
|
|
|
|
}
|
|
|
|
|
if (aflag && index (fci->flag_chars, 'a') == 0)
|
|
|
|
|
{
|
|
|
|
|
sprintf (message, "`a' flag used with `%c' format",
|
|
|
|
|
format_char);
|
|
|
|
|
warning (message);
|
|
|
|
|
}
|
|
|
|
|
if (info->is_scan && format_char == '[')
|
|
|
|
|
{
|
|
|
|
|
/* Skip over scan set, in case it happens to have '%' in it. */
|
|
|
|
|
if (*format_chars == '^')
|
|
|
|
|
++format_chars;
|
|
|
|
|
/* Find closing bracket; if one is hit immediately, then
|
|
|
|
|
it's part of the scan set rather than a terminator. */
|
|
|
|
|
if (*format_chars == ']')
|
|
|
|
|
++format_chars;
|
|
|
|
|
while (*format_chars && *format_chars != ']')
|
|
|
|
|
++format_chars;
|
|
|
|
|
if (*format_chars != ']')
|
|
|
|
|
/* The end of the format string was reached. */
|
|
|
|
|
warning ("no closing `]' for `%%[' format");
|
|
|
|
|
}
|
|
|
|
|
if (suppressed)
|
|
|
|
|
{
|
|
|
|
|
if (index (fci->flag_chars, '*') == 0)
|
|
|
|
|
{
|
|
|
|
|
sprintf (message,
|
|
|
|
|
"suppression of `%c' conversion in format",
|
|
|
|
|
format_char);
|
|
|
|
|
warning (message);
|
|
|
|
|
}
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
for (i = 0; flag_chars[i] != 0; ++i)
|
|
|
|
|
{
|
|
|
|
|
if (index (fci->flag_chars, flag_chars[i]) == 0)
|
|
|
|
|
{
|
|
|
|
|
sprintf (message, "flag `%c' used with type `%c'",
|
|
|
|
|
flag_chars[i], format_char);
|
|
|
|
|
warning (message);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (precise && index (flag_chars, '0') != 0
|
|
|
|
|
&& (format_char == 'd' || format_char == 'i'
|
|
|
|
|
|| format_char == 'o' || format_char == 'u'
|
|
|
|
|
|| format_char == 'x' || format_char == 'x'))
|
|
|
|
|
{
|
|
|
|
|
sprintf (message,
|
|
|
|
|
"precision and `0' flag not both allowed with `%c' format",
|
|
|
|
|
format_char);
|
|
|
|
|
warning (message);
|
|
|
|
|
}
|
|
|
|
|
switch (length_char)
|
|
|
|
|
{
|
|
|
|
|
default: wanted_type = fci->nolen ? *(fci->nolen) : 0; break;
|
|
|
|
|
case 'h': wanted_type = fci->hlen ? *(fci->hlen) : 0; break;
|
|
|
|
|
case 'l': wanted_type = fci->llen ? *(fci->llen) : 0; break;
|
1994-09-18 21:25:02 +00:00
|
|
|
|
case 'q': wanted_type = fci->qlen ? *(fci->qlen) : 0; break;
|
1994-08-02 20:15:59 +00:00
|
|
|
|
case 'L': wanted_type = fci->bigllen ? *(fci->bigllen) : 0; break;
|
|
|
|
|
}
|
|
|
|
|
if (wanted_type == 0)
|
|
|
|
|
{
|
|
|
|
|
sprintf (message,
|
|
|
|
|
"use of `%c' length character with `%c' type character",
|
|
|
|
|
length_char, format_char);
|
|
|
|
|
warning (message);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
** XXX -- should kvetch about stuff such as
|
|
|
|
|
** {
|
|
|
|
|
** const int i;
|
|
|
|
|
**
|
|
|
|
|
** scanf ("%d", &i);
|
|
|
|
|
** }
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/* Finally. . .check type of argument against desired type! */
|
|
|
|
|
if (info->first_arg_num == 0)
|
|
|
|
|
continue;
|
|
|
|
|
if (params == 0)
|
|
|
|
|
{
|
|
|
|
|
warning (tfaff);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
cur_param = TREE_VALUE (params);
|
|
|
|
|
params = TREE_CHAIN (params);
|
|
|
|
|
++arg_num;
|
|
|
|
|
cur_type = TREE_TYPE (cur_param);
|
|
|
|
|
|
|
|
|
|
/* Check the types of any additional pointer arguments
|
|
|
|
|
that precede the "real" argument. */
|
|
|
|
|
for (i = 0; i < fci->pointer_count; ++i)
|
|
|
|
|
{
|
|
|
|
|
if (TREE_CODE (cur_type) == POINTER_TYPE)
|
|
|
|
|
{
|
|
|
|
|
cur_type = TREE_TYPE (cur_type);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
sprintf (message,
|
|
|
|
|
"format argument is not a %s (arg %d)",
|
|
|
|
|
((fci->pointer_count == 1) ? "pointer" : "pointer to a pointer"),
|
|
|
|
|
arg_num);
|
|
|
|
|
warning (message);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Check the type of the "real" argument, if there's a type we want. */
|
|
|
|
|
if (i == fci->pointer_count && wanted_type != 0
|
|
|
|
|
&& wanted_type != TYPE_MAIN_VARIANT (cur_type)
|
|
|
|
|
/* If we want `void *', allow any pointer type.
|
|
|
|
|
(Anything else would already have got a warning.) */
|
|
|
|
|
&& ! (wanted_type == void_type_node
|
|
|
|
|
&& fci->pointer_count > 0)
|
|
|
|
|
/* Don't warn about differences merely in signedness. */
|
|
|
|
|
&& !(TREE_CODE (wanted_type) == INTEGER_TYPE
|
|
|
|
|
&& TREE_CODE (TYPE_MAIN_VARIANT (cur_type)) == INTEGER_TYPE
|
|
|
|
|
&& (TREE_UNSIGNED (wanted_type)
|
|
|
|
|
? wanted_type == (cur_type = unsigned_type (cur_type))
|
|
|
|
|
: wanted_type == (cur_type = signed_type (cur_type))))
|
|
|
|
|
/* Likewise, "signed char", "unsigned char" and "char" are
|
|
|
|
|
equivalent but the above test won't consider them equivalent. */
|
|
|
|
|
&& ! (wanted_type == char_type_node
|
|
|
|
|
&& (TYPE_MAIN_VARIANT (cur_type) == signed_char_type_node
|
|
|
|
|
|| TYPE_MAIN_VARIANT (cur_type) == unsigned_char_type_node)))
|
|
|
|
|
{
|
|
|
|
|
register char *this;
|
|
|
|
|
register char *that;
|
1995-05-30 05:05:38 +00:00
|
|
|
|
|
1994-08-02 20:15:59 +00:00
|
|
|
|
this = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (wanted_type)));
|
|
|
|
|
that = 0;
|
|
|
|
|
if (TREE_CODE (cur_type) != ERROR_MARK
|
|
|
|
|
&& TYPE_NAME (cur_type) != 0
|
|
|
|
|
&& TREE_CODE (cur_type) != INTEGER_TYPE
|
|
|
|
|
&& !(TREE_CODE (cur_type) == POINTER_TYPE
|
|
|
|
|
&& TREE_CODE (TREE_TYPE (cur_type)) == INTEGER_TYPE))
|
|
|
|
|
{
|
|
|
|
|
if (TREE_CODE (TYPE_NAME (cur_type)) == TYPE_DECL
|
|
|
|
|
&& DECL_NAME (TYPE_NAME (cur_type)) != 0)
|
|
|
|
|
that = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (cur_type)));
|
|
|
|
|
else
|
|
|
|
|
that = IDENTIFIER_POINTER (TYPE_NAME (cur_type));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* A nameless type can't possibly match what the format wants.
|
|
|
|
|
So there will be a warning for it.
|
|
|
|
|
Make up a string to describe vaguely what it is. */
|
|
|
|
|
if (that == 0)
|
|
|
|
|
{
|
|
|
|
|
if (TREE_CODE (cur_type) == POINTER_TYPE)
|
|
|
|
|
that = "pointer";
|
|
|
|
|
else
|
|
|
|
|
that = "different type";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Make the warning better in case of mismatch of int vs long. */
|
|
|
|
|
if (TREE_CODE (cur_type) == INTEGER_TYPE
|
|
|
|
|
&& TREE_CODE (wanted_type) == INTEGER_TYPE
|
|
|
|
|
&& TYPE_PRECISION (cur_type) == TYPE_PRECISION (wanted_type)
|
|
|
|
|
&& TYPE_NAME (cur_type) != 0
|
|
|
|
|
&& TREE_CODE (TYPE_NAME (cur_type)) == TYPE_DECL)
|
|
|
|
|
that = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (cur_type)));
|
|
|
|
|
|
|
|
|
|
if (strcmp (this, that) != 0)
|
|
|
|
|
{
|
|
|
|
|
sprintf (message, "%s format, %s arg (arg %d)",
|
|
|
|
|
this, that, arg_num);
|
|
|
|
|
warning (message);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Print a warning if a constant expression had overflow in folding.
|
|
|
|
|
Invoke this function on every expression that the language
|
|
|
|
|
requires to be a constant expression.
|
|
|
|
|
Note the ANSI C standard says it is erroneous for a
|
|
|
|
|
constant expression to overflow. */
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
constant_expression_warning (value)
|
|
|
|
|
tree value;
|
|
|
|
|
{
|
|
|
|
|
if ((TREE_CODE (value) == INTEGER_CST || TREE_CODE (value) == REAL_CST
|
|
|
|
|
|| TREE_CODE (value) == COMPLEX_CST)
|
|
|
|
|
&& TREE_CONSTANT_OVERFLOW (value) && pedantic)
|
|
|
|
|
pedwarn ("overflow in constant expression");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Print a warning if an expression had overflow in folding.
|
|
|
|
|
Invoke this function on every expression that
|
|
|
|
|
(1) appears in the source code, and
|
|
|
|
|
(2) might be a constant expression that overflowed, and
|
|
|
|
|
(3) is not already checked by convert_and_check;
|
|
|
|
|
however, do not invoke this function on operands of explicit casts. */
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
overflow_warning (value)
|
|
|
|
|
tree value;
|
|
|
|
|
{
|
|
|
|
|
if ((TREE_CODE (value) == INTEGER_CST
|
|
|
|
|
|| (TREE_CODE (value) == COMPLEX_CST
|
|
|
|
|
&& TREE_CODE (TREE_REALPART (value)) == INTEGER_CST))
|
|
|
|
|
&& TREE_OVERFLOW (value))
|
|
|
|
|
{
|
|
|
|
|
TREE_OVERFLOW (value) = 0;
|
|
|
|
|
warning ("integer overflow in expression");
|
|
|
|
|
}
|
|
|
|
|
else if ((TREE_CODE (value) == REAL_CST
|
|
|
|
|
|| (TREE_CODE (value) == COMPLEX_CST
|
|
|
|
|
&& TREE_CODE (TREE_REALPART (value)) == REAL_CST))
|
|
|
|
|
&& TREE_OVERFLOW (value))
|
|
|
|
|
{
|
|
|
|
|
TREE_OVERFLOW (value) = 0;
|
|
|
|
|
warning ("floating-pointer overflow in expression");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Print a warning if a large constant is truncated to unsigned,
|
|
|
|
|
or if -Wconversion is used and a constant < 0 is converted to unsigned.
|
|
|
|
|
Invoke this function on every expression that might be implicitly
|
|
|
|
|
converted to an unsigned type. */
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
unsigned_conversion_warning (result, operand)
|
|
|
|
|
tree result, operand;
|
|
|
|
|
{
|
|
|
|
|
if (TREE_CODE (operand) == INTEGER_CST
|
|
|
|
|
&& TREE_CODE (TREE_TYPE (result)) == INTEGER_TYPE
|
|
|
|
|
&& TREE_UNSIGNED (TREE_TYPE (result))
|
|
|
|
|
&& !int_fits_type_p (operand, TREE_TYPE (result)))
|
|
|
|
|
{
|
|
|
|
|
if (!int_fits_type_p (operand, signed_type (TREE_TYPE (result))))
|
|
|
|
|
/* This detects cases like converting -129 or 256 to unsigned char. */
|
|
|
|
|
warning ("large integer implicitly truncated to unsigned type");
|
|
|
|
|
else if (warn_conversion)
|
|
|
|
|
warning ("negative integer implicitly converted to unsigned type");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Convert EXPR to TYPE, warning about conversion problems with constants.
|
|
|
|
|
Invoke this function on every expression that is converted implicitly,
|
|
|
|
|
i.e. because of language rules and not because of an explicit cast. */
|
|
|
|
|
|
|
|
|
|
tree
|
|
|
|
|
convert_and_check (type, expr)
|
|
|
|
|
tree type, expr;
|
|
|
|
|
{
|
|
|
|
|
tree t = convert (type, expr);
|
|
|
|
|
if (TREE_CODE (t) == INTEGER_CST)
|
|
|
|
|
{
|
|
|
|
|
if (TREE_OVERFLOW (t))
|
|
|
|
|
{
|
|
|
|
|
TREE_OVERFLOW (t) = 0;
|
|
|
|
|
|
|
|
|
|
/* No warning for converting 0x80000000 to int. */
|
|
|
|
|
if (!(TREE_UNSIGNED (type) < TREE_UNSIGNED (TREE_TYPE (expr))
|
|
|
|
|
&& TREE_CODE (TREE_TYPE (expr)) == INTEGER_TYPE
|
|
|
|
|
&& TYPE_PRECISION (type) == TYPE_PRECISION (TREE_TYPE (expr))))
|
|
|
|
|
/* If EXPR fits in the unsigned version of TYPE,
|
|
|
|
|
don't warn unless pedantic. */
|
|
|
|
|
if (pedantic
|
|
|
|
|
|| TREE_UNSIGNED (type)
|
|
|
|
|
|| ! int_fits_type_p (expr, unsigned_type (type)))
|
|
|
|
|
warning ("overflow in implicit constant conversion");
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
unsigned_conversion_warning (t, expr);
|
|
|
|
|
}
|
|
|
|
|
return t;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
c_expand_expr_stmt (expr)
|
|
|
|
|
tree expr;
|
|
|
|
|
{
|
|
|
|
|
/* Do default conversion if safe and possibly important,
|
|
|
|
|
in case within ({...}). */
|
|
|
|
|
if ((TREE_CODE (TREE_TYPE (expr)) == ARRAY_TYPE && lvalue_p (expr))
|
|
|
|
|
|| TREE_CODE (TREE_TYPE (expr)) == FUNCTION_TYPE)
|
|
|
|
|
expr = default_conversion (expr);
|
|
|
|
|
|
|
|
|
|
if (TREE_TYPE (expr) != error_mark_node
|
|
|
|
|
&& TYPE_SIZE (TREE_TYPE (expr)) == 0
|
|
|
|
|
&& TREE_CODE (TREE_TYPE (expr)) != ARRAY_TYPE)
|
|
|
|
|
error ("expression statement has incomplete type");
|
|
|
|
|
|
|
|
|
|
expand_expr_stmt (expr);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Validate the expression after `case' and apply default promotions. */
|
|
|
|
|
|
|
|
|
|
tree
|
|
|
|
|
check_case_value (value)
|
|
|
|
|
tree value;
|
|
|
|
|
{
|
|
|
|
|
if (value == NULL_TREE)
|
|
|
|
|
return value;
|
|
|
|
|
|
|
|
|
|
/* Strip NON_LVALUE_EXPRs since we aren't using as an lvalue. */
|
|
|
|
|
STRIP_TYPE_NOPS (value);
|
|
|
|
|
|
|
|
|
|
if (TREE_CODE (value) != INTEGER_CST
|
|
|
|
|
&& 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;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Return an integer type with BITS bits of precision,
|
|
|
|
|
that is unsigned if UNSIGNEDP is nonzero, otherwise signed. */
|
|
|
|
|
|
|
|
|
|
tree
|
|
|
|
|
type_for_size (bits, unsignedp)
|
|
|
|
|
unsigned bits;
|
|
|
|
|
int unsignedp;
|
|
|
|
|
{
|
|
|
|
|
if (bits == TYPE_PRECISION (signed_char_type_node))
|
|
|
|
|
return unsignedp ? unsigned_char_type_node : signed_char_type_node;
|
|
|
|
|
|
|
|
|
|
if (bits == TYPE_PRECISION (short_integer_type_node))
|
|
|
|
|
return unsignedp ? short_unsigned_type_node : short_integer_type_node;
|
|
|
|
|
|
|
|
|
|
if (bits == TYPE_PRECISION (integer_type_node))
|
|
|
|
|
return unsignedp ? unsigned_type_node : integer_type_node;
|
|
|
|
|
|
|
|
|
|
if (bits == TYPE_PRECISION (long_integer_type_node))
|
|
|
|
|
return unsignedp ? long_unsigned_type_node : long_integer_type_node;
|
|
|
|
|
|
|
|
|
|
if (bits == TYPE_PRECISION (long_long_integer_type_node))
|
|
|
|
|
return (unsignedp ? long_long_unsigned_type_node
|
|
|
|
|
: long_long_integer_type_node);
|
|
|
|
|
|
|
|
|
|
if (bits <= TYPE_PRECISION (intQI_type_node))
|
|
|
|
|
return unsignedp ? unsigned_intQI_type_node : intQI_type_node;
|
|
|
|
|
|
|
|
|
|
if (bits <= TYPE_PRECISION (intHI_type_node))
|
|
|
|
|
return unsignedp ? unsigned_intHI_type_node : intHI_type_node;
|
|
|
|
|
|
|
|
|
|
if (bits <= TYPE_PRECISION (intSI_type_node))
|
|
|
|
|
return unsignedp ? unsigned_intSI_type_node : intSI_type_node;
|
|
|
|
|
|
|
|
|
|
if (bits <= TYPE_PRECISION (intDI_type_node))
|
|
|
|
|
return unsignedp ? unsigned_intDI_type_node : intDI_type_node;
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Return a data type that has machine mode MODE.
|
|
|
|
|
If the mode is an integer,
|
|
|
|
|
then UNSIGNEDP selects between signed and unsigned types. */
|
|
|
|
|
|
|
|
|
|
tree
|
|
|
|
|
type_for_mode (mode, unsignedp)
|
|
|
|
|
enum machine_mode mode;
|
|
|
|
|
int unsignedp;
|
|
|
|
|
{
|
|
|
|
|
if (mode == TYPE_MODE (signed_char_type_node))
|
|
|
|
|
return unsignedp ? unsigned_char_type_node : signed_char_type_node;
|
|
|
|
|
|
|
|
|
|
if (mode == TYPE_MODE (short_integer_type_node))
|
|
|
|
|
return unsignedp ? short_unsigned_type_node : short_integer_type_node;
|
|
|
|
|
|
|
|
|
|
if (mode == TYPE_MODE (integer_type_node))
|
|
|
|
|
return unsignedp ? unsigned_type_node : integer_type_node;
|
|
|
|
|
|
|
|
|
|
if (mode == TYPE_MODE (long_integer_type_node))
|
|
|
|
|
return unsignedp ? long_unsigned_type_node : long_integer_type_node;
|
|
|
|
|
|
|
|
|
|
if (mode == TYPE_MODE (long_long_integer_type_node))
|
|
|
|
|
return unsignedp ? long_long_unsigned_type_node : long_long_integer_type_node;
|
|
|
|
|
|
|
|
|
|
if (mode == TYPE_MODE (intQI_type_node))
|
|
|
|
|
return unsignedp ? unsigned_intQI_type_node : intQI_type_node;
|
|
|
|
|
|
|
|
|
|
if (mode == TYPE_MODE (intHI_type_node))
|
|
|
|
|
return unsignedp ? unsigned_intHI_type_node : intHI_type_node;
|
|
|
|
|
|
|
|
|
|
if (mode == TYPE_MODE (intSI_type_node))
|
|
|
|
|
return unsignedp ? unsigned_intSI_type_node : intSI_type_node;
|
|
|
|
|
|
|
|
|
|
if (mode == TYPE_MODE (intDI_type_node))
|
|
|
|
|
return unsignedp ? unsigned_intDI_type_node : intDI_type_node;
|
|
|
|
|
|
|
|
|
|
if (mode == TYPE_MODE (float_type_node))
|
|
|
|
|
return float_type_node;
|
|
|
|
|
|
|
|
|
|
if (mode == TYPE_MODE (double_type_node))
|
|
|
|
|
return double_type_node;
|
|
|
|
|
|
|
|
|
|
if (mode == TYPE_MODE (long_double_type_node))
|
|
|
|
|
return long_double_type_node;
|
|
|
|
|
|
|
|
|
|
if (mode == TYPE_MODE (build_pointer_type (char_type_node)))
|
|
|
|
|
return build_pointer_type (char_type_node);
|
|
|
|
|
|
|
|
|
|
if (mode == TYPE_MODE (build_pointer_type (integer_type_node)))
|
|
|
|
|
return build_pointer_type (integer_type_node);
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
----------------------------------
GCC-2.6.1 COMES TO FREEBSD-current
----------------------------------
Everybody needs to 'make world'.
Oakland, Nov 2nd 1994. In a surprise move this sunny afternoon, the release-
engineer for the slightly delayed FreeBSD-2.0, Poul-Henning Kamp (28),
decided to pull in the new version 2.6.1 of the GNU C-compiler.
The new version of the compiler was release today at noon, and hardly 9
hours later it was committed into the FreeBSD-current source-repository.
"It's is simply because we have had too much trouble with the version 2.6.0
of the compiler" Poul-Henning told the FreeBSD-Gazette, "we took a gamble
when we decided to use that as our compiler for the 2.0 release, but it
seems to pay of in the end now" he concludes.
The move has not been discussed on the "core" list at all, and will come as
a surprise for most Poul-Hennings peers. "I have only discussed it with
Jordan [J. K. Hubbard, the FreeBSD's resident humourist], and we agreed that
we needed to do it, so ... I did it!". After a breath he added with a grin:
"My email will probably get an all time 'disk-full' now!".
This will bring quite a flag-day to the FreeBSD developers, the patch-file
is almost 1.4 Megabyte, and they will have to run "make world" to get
entirely -current again. "Too bad, but we just had to do this." Was
the only comment from Poul-Henning to these problems.
When asked how this move would impact the 2.0 release-date, Poul-Hennings
face grew dark, he mumbled some very Danish words while he moved his fingers
in strange geometrical patterns. Immediately something ecclipsed the Sun, a
minor tremor shook the buildings, and the temperature fell significantly.
We decided not to pursure the question.
-----------
JOB-SECTION
-----------
Are you a dedicated GCC-hacker ?
We BADLY need somebody to look at the 'freebsd' OS in gcc, sanitize it and
carry the patches back to the GNU people. In particular, we need to get
out of the "i386-only" spot we are in now. I have the stuff to take a
gnu-dist into bmake-form, and will do that part.
Please apply to phk@freebsd.org
No Novice Need Apply.
1994-11-03 06:52:42 +00:00
|
|
|
|
/* Return the minimum number of bits needed to represent VALUE in a
|
|
|
|
|
signed or unsigned type, UNSIGNEDP says which. */
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
min_precision (value, unsignedp)
|
|
|
|
|
tree value;
|
|
|
|
|
int unsignedp;
|
|
|
|
|
{
|
|
|
|
|
int log;
|
|
|
|
|
|
|
|
|
|
/* If the value is negative, compute its negative minus 1. The latter
|
|
|
|
|
adjustment is because the absolute value of the largest negative value
|
|
|
|
|
is one larger than the largest positive value. This is equivalent to
|
|
|
|
|
a bit-wise negation, so use that operation instead. */
|
|
|
|
|
|
|
|
|
|
if (tree_int_cst_sgn (value) < 0)
|
|
|
|
|
value = fold (build1 (BIT_NOT_EXPR, TREE_TYPE (value), value));
|
|
|
|
|
|
|
|
|
|
/* Return the number of bits needed, taking into account the fact
|
|
|
|
|
that we need one more bit for a signed than unsigned type. */
|
|
|
|
|
|
|
|
|
|
if (integer_zerop (value))
|
|
|
|
|
log = 0;
|
|
|
|
|
else if (TREE_INT_CST_HIGH (value) != 0)
|
|
|
|
|
log = HOST_BITS_PER_WIDE_INT + floor_log2 (TREE_INT_CST_HIGH (value));
|
|
|
|
|
else
|
|
|
|
|
log = floor_log2 (TREE_INT_CST_LOW (value));
|
|
|
|
|
|
|
|
|
|
return log + 1 + ! unsignedp;
|
|
|
|
|
}
|
|
|
|
|
|
1994-08-02 20:15:59 +00:00
|
|
|
|
/* Print an error message for invalid operands to arith operation CODE.
|
|
|
|
|
NOP_EXPR is used as a special case (see truthvalue_conversion). */
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
binary_op_error (code)
|
|
|
|
|
enum tree_code code;
|
|
|
|
|
{
|
|
|
|
|
register char *opname = "unknown";
|
|
|
|
|
|
|
|
|
|
switch (code)
|
|
|
|
|
{
|
|
|
|
|
case NOP_EXPR:
|
|
|
|
|
error ("invalid truth-value expression");
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
case PLUS_EXPR:
|
|
|
|
|
opname = "+"; break;
|
|
|
|
|
case MINUS_EXPR:
|
|
|
|
|
opname = "-"; break;
|
|
|
|
|
case MULT_EXPR:
|
|
|
|
|
opname = "*"; break;
|
|
|
|
|
case MAX_EXPR:
|
|
|
|
|
opname = "max"; break;
|
|
|
|
|
case MIN_EXPR:
|
|
|
|
|
opname = "min"; break;
|
|
|
|
|
case EQ_EXPR:
|
|
|
|
|
opname = "=="; break;
|
|
|
|
|
case NE_EXPR:
|
|
|
|
|
opname = "!="; break;
|
|
|
|
|
case LE_EXPR:
|
|
|
|
|
opname = "<="; break;
|
|
|
|
|
case GE_EXPR:
|
|
|
|
|
opname = ">="; break;
|
|
|
|
|
case LT_EXPR:
|
|
|
|
|
opname = "<"; break;
|
|
|
|
|
case GT_EXPR:
|
|
|
|
|
opname = ">"; break;
|
|
|
|
|
case LSHIFT_EXPR:
|
|
|
|
|
opname = "<<"; break;
|
|
|
|
|
case RSHIFT_EXPR:
|
|
|
|
|
opname = ">>"; break;
|
|
|
|
|
case TRUNC_MOD_EXPR:
|
|
|
|
|
case FLOOR_MOD_EXPR:
|
|
|
|
|
opname = "%"; break;
|
|
|
|
|
case TRUNC_DIV_EXPR:
|
|
|
|
|
case FLOOR_DIV_EXPR:
|
|
|
|
|
opname = "/"; break;
|
|
|
|
|
case BIT_AND_EXPR:
|
|
|
|
|
opname = "&"; break;
|
|
|
|
|
case BIT_IOR_EXPR:
|
|
|
|
|
opname = "|"; break;
|
|
|
|
|
case TRUTH_ANDIF_EXPR:
|
|
|
|
|
opname = "&&"; break;
|
|
|
|
|
case TRUTH_ORIF_EXPR:
|
|
|
|
|
opname = "||"; break;
|
|
|
|
|
case BIT_XOR_EXPR:
|
|
|
|
|
opname = "^"; break;
|
|
|
|
|
case LROTATE_EXPR:
|
|
|
|
|
case RROTATE_EXPR:
|
|
|
|
|
opname = "rotate"; break;
|
|
|
|
|
}
|
|
|
|
|
error ("invalid operands to binary %s", opname);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Subroutine of build_binary_op, used for comparison operations.
|
|
|
|
|
See if the operands have both been converted from subword integer types
|
|
|
|
|
and, if so, perhaps change them both back to their original type.
|
|
|
|
|
This function is also responsible for converting the two operands
|
|
|
|
|
to the proper common type for comparison.
|
|
|
|
|
|
|
|
|
|
The arguments of this function are all pointers to local variables
|
|
|
|
|
of build_binary_op: OP0_PTR is &OP0, OP1_PTR is &OP1,
|
|
|
|
|
RESTYPE_PTR is &RESULT_TYPE and RESCODE_PTR is &RESULTCODE.
|
|
|
|
|
|
|
|
|
|
If this function returns nonzero, it means that the comparison has
|
|
|
|
|
a constant value. What this function returns is an expression for
|
|
|
|
|
that value. */
|
|
|
|
|
|
|
|
|
|
tree
|
|
|
|
|
shorten_compare (op0_ptr, op1_ptr, restype_ptr, rescode_ptr)
|
|
|
|
|
tree *op0_ptr, *op1_ptr;
|
|
|
|
|
tree *restype_ptr;
|
|
|
|
|
enum tree_code *rescode_ptr;
|
|
|
|
|
{
|
|
|
|
|
register tree type;
|
|
|
|
|
tree op0 = *op0_ptr;
|
|
|
|
|
tree op1 = *op1_ptr;
|
|
|
|
|
int unsignedp0, unsignedp1;
|
|
|
|
|
int real1, real2;
|
|
|
|
|
tree primop0, primop1;
|
|
|
|
|
enum tree_code code = *rescode_ptr;
|
|
|
|
|
|
|
|
|
|
/* Throw away any conversions to wider types
|
|
|
|
|
already present in the operands. */
|
|
|
|
|
|
|
|
|
|
primop0 = get_narrower (op0, &unsignedp0);
|
|
|
|
|
primop1 = get_narrower (op1, &unsignedp1);
|
|
|
|
|
|
|
|
|
|
/* Handle the case that OP0 does not *contain* a conversion
|
|
|
|
|
but it *requires* conversion to FINAL_TYPE. */
|
|
|
|
|
|
|
|
|
|
if (op0 == primop0 && TREE_TYPE (op0) != *restype_ptr)
|
|
|
|
|
unsignedp0 = TREE_UNSIGNED (TREE_TYPE (op0));
|
|
|
|
|
if (op1 == primop1 && TREE_TYPE (op1) != *restype_ptr)
|
|
|
|
|
unsignedp1 = TREE_UNSIGNED (TREE_TYPE (op1));
|
|
|
|
|
|
|
|
|
|
/* If one of the operands must be floated, we cannot optimize. */
|
|
|
|
|
real1 = TREE_CODE (TREE_TYPE (primop0)) == REAL_TYPE;
|
|
|
|
|
real2 = TREE_CODE (TREE_TYPE (primop1)) == REAL_TYPE;
|
|
|
|
|
|
|
|
|
|
/* If first arg is constant, swap the args (changing operation
|
----------------------------------
GCC-2.6.1 COMES TO FREEBSD-current
----------------------------------
Everybody needs to 'make world'.
Oakland, Nov 2nd 1994. In a surprise move this sunny afternoon, the release-
engineer for the slightly delayed FreeBSD-2.0, Poul-Henning Kamp (28),
decided to pull in the new version 2.6.1 of the GNU C-compiler.
The new version of the compiler was release today at noon, and hardly 9
hours later it was committed into the FreeBSD-current source-repository.
"It's is simply because we have had too much trouble with the version 2.6.0
of the compiler" Poul-Henning told the FreeBSD-Gazette, "we took a gamble
when we decided to use that as our compiler for the 2.0 release, but it
seems to pay of in the end now" he concludes.
The move has not been discussed on the "core" list at all, and will come as
a surprise for most Poul-Hennings peers. "I have only discussed it with
Jordan [J. K. Hubbard, the FreeBSD's resident humourist], and we agreed that
we needed to do it, so ... I did it!". After a breath he added with a grin:
"My email will probably get an all time 'disk-full' now!".
This will bring quite a flag-day to the FreeBSD developers, the patch-file
is almost 1.4 Megabyte, and they will have to run "make world" to get
entirely -current again. "Too bad, but we just had to do this." Was
the only comment from Poul-Henning to these problems.
When asked how this move would impact the 2.0 release-date, Poul-Hennings
face grew dark, he mumbled some very Danish words while he moved his fingers
in strange geometrical patterns. Immediately something ecclipsed the Sun, a
minor tremor shook the buildings, and the temperature fell significantly.
We decided not to pursure the question.
-----------
JOB-SECTION
-----------
Are you a dedicated GCC-hacker ?
We BADLY need somebody to look at the 'freebsd' OS in gcc, sanitize it and
carry the patches back to the GNU people. In particular, we need to get
out of the "i386-only" spot we are in now. I have the stuff to take a
gnu-dist into bmake-form, and will do that part.
Please apply to phk@freebsd.org
No Novice Need Apply.
1994-11-03 06:52:42 +00:00
|
|
|
|
so value is preserved), for canonicalization. Don't do this if
|
|
|
|
|
the second arg is 0. */
|
1994-08-02 20:15:59 +00:00
|
|
|
|
|
----------------------------------
GCC-2.6.1 COMES TO FREEBSD-current
----------------------------------
Everybody needs to 'make world'.
Oakland, Nov 2nd 1994. In a surprise move this sunny afternoon, the release-
engineer for the slightly delayed FreeBSD-2.0, Poul-Henning Kamp (28),
decided to pull in the new version 2.6.1 of the GNU C-compiler.
The new version of the compiler was release today at noon, and hardly 9
hours later it was committed into the FreeBSD-current source-repository.
"It's is simply because we have had too much trouble with the version 2.6.0
of the compiler" Poul-Henning told the FreeBSD-Gazette, "we took a gamble
when we decided to use that as our compiler for the 2.0 release, but it
seems to pay of in the end now" he concludes.
The move has not been discussed on the "core" list at all, and will come as
a surprise for most Poul-Hennings peers. "I have only discussed it with
Jordan [J. K. Hubbard, the FreeBSD's resident humourist], and we agreed that
we needed to do it, so ... I did it!". After a breath he added with a grin:
"My email will probably get an all time 'disk-full' now!".
This will bring quite a flag-day to the FreeBSD developers, the patch-file
is almost 1.4 Megabyte, and they will have to run "make world" to get
entirely -current again. "Too bad, but we just had to do this." Was
the only comment from Poul-Henning to these problems.
When asked how this move would impact the 2.0 release-date, Poul-Hennings
face grew dark, he mumbled some very Danish words while he moved his fingers
in strange geometrical patterns. Immediately something ecclipsed the Sun, a
minor tremor shook the buildings, and the temperature fell significantly.
We decided not to pursure the question.
-----------
JOB-SECTION
-----------
Are you a dedicated GCC-hacker ?
We BADLY need somebody to look at the 'freebsd' OS in gcc, sanitize it and
carry the patches back to the GNU people. In particular, we need to get
out of the "i386-only" spot we are in now. I have the stuff to take a
gnu-dist into bmake-form, and will do that part.
Please apply to phk@freebsd.org
No Novice Need Apply.
1994-11-03 06:52:42 +00:00
|
|
|
|
if (TREE_CONSTANT (primop0)
|
|
|
|
|
&& ! integer_zerop (primop1) && ! real_zerop (primop1))
|
1994-08-02 20:15:59 +00:00
|
|
|
|
{
|
|
|
|
|
register tree tem = primop0;
|
|
|
|
|
register int temi = unsignedp0;
|
|
|
|
|
primop0 = primop1;
|
|
|
|
|
primop1 = tem;
|
|
|
|
|
tem = op0;
|
|
|
|
|
op0 = op1;
|
|
|
|
|
op1 = tem;
|
|
|
|
|
*op0_ptr = op0;
|
|
|
|
|
*op1_ptr = op1;
|
|
|
|
|
unsignedp0 = unsignedp1;
|
|
|
|
|
unsignedp1 = temi;
|
|
|
|
|
temi = real1;
|
|
|
|
|
real1 = real2;
|
|
|
|
|
real2 = temi;
|
|
|
|
|
|
|
|
|
|
switch (code)
|
|
|
|
|
{
|
|
|
|
|
case LT_EXPR:
|
|
|
|
|
code = GT_EXPR;
|
|
|
|
|
break;
|
|
|
|
|
case GT_EXPR:
|
|
|
|
|
code = LT_EXPR;
|
|
|
|
|
break;
|
|
|
|
|
case LE_EXPR:
|
|
|
|
|
code = GE_EXPR;
|
|
|
|
|
break;
|
|
|
|
|
case GE_EXPR:
|
|
|
|
|
code = LE_EXPR;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
*rescode_ptr = code;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* If comparing an integer against a constant more bits wide,
|
|
|
|
|
maybe we can deduce a value of 1 or 0 independent of the data.
|
|
|
|
|
Or else truncate the constant now
|
|
|
|
|
rather than extend the variable at run time.
|
|
|
|
|
|
|
|
|
|
This is only interesting if the constant is the wider arg.
|
|
|
|
|
Also, it is not safe if the constant is unsigned and the
|
|
|
|
|
variable arg is signed, since in this case the variable
|
|
|
|
|
would be sign-extended and then regarded as unsigned.
|
|
|
|
|
Our technique fails in this case because the lowest/highest
|
|
|
|
|
possible unsigned results don't follow naturally from the
|
|
|
|
|
lowest/highest possible values of the variable operand.
|
|
|
|
|
For just EQ_EXPR and NE_EXPR there is another technique that
|
|
|
|
|
could be used: see if the constant can be faithfully represented
|
|
|
|
|
in the other operand's type, by truncating it and reextending it
|
|
|
|
|
and see if that preserves the constant's value. */
|
|
|
|
|
|
|
|
|
|
if (!real1 && !real2
|
|
|
|
|
&& TREE_CODE (primop1) == INTEGER_CST
|
|
|
|
|
&& TYPE_PRECISION (TREE_TYPE (primop0)) < TYPE_PRECISION (*restype_ptr))
|
|
|
|
|
{
|
|
|
|
|
int min_gt, max_gt, min_lt, max_lt;
|
|
|
|
|
tree maxval, minval;
|
|
|
|
|
/* 1 if comparison is nominally unsigned. */
|
|
|
|
|
int unsignedp = TREE_UNSIGNED (*restype_ptr);
|
|
|
|
|
tree val;
|
|
|
|
|
|
|
|
|
|
type = signed_or_unsigned_type (unsignedp0, TREE_TYPE (primop0));
|
|
|
|
|
|
|
|
|
|
maxval = TYPE_MAX_VALUE (type);
|
|
|
|
|
minval = TYPE_MIN_VALUE (type);
|
|
|
|
|
|
|
|
|
|
if (unsignedp && !unsignedp0)
|
|
|
|
|
*restype_ptr = signed_type (*restype_ptr);
|
|
|
|
|
|
|
|
|
|
if (TREE_TYPE (primop1) != *restype_ptr)
|
|
|
|
|
primop1 = convert (*restype_ptr, primop1);
|
|
|
|
|
if (type != *restype_ptr)
|
|
|
|
|
{
|
|
|
|
|
minval = convert (*restype_ptr, minval);
|
|
|
|
|
maxval = convert (*restype_ptr, maxval);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (unsignedp && unsignedp0)
|
|
|
|
|
{
|
|
|
|
|
min_gt = INT_CST_LT_UNSIGNED (primop1, minval);
|
|
|
|
|
max_gt = INT_CST_LT_UNSIGNED (primop1, maxval);
|
|
|
|
|
min_lt = INT_CST_LT_UNSIGNED (minval, primop1);
|
|
|
|
|
max_lt = INT_CST_LT_UNSIGNED (maxval, primop1);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
min_gt = INT_CST_LT (primop1, minval);
|
|
|
|
|
max_gt = INT_CST_LT (primop1, maxval);
|
|
|
|
|
min_lt = INT_CST_LT (minval, primop1);
|
|
|
|
|
max_lt = INT_CST_LT (maxval, primop1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
val = 0;
|
|
|
|
|
/* This used to be a switch, but Genix compiler can't handle that. */
|
|
|
|
|
if (code == NE_EXPR)
|
|
|
|
|
{
|
|
|
|
|
if (max_lt || min_gt)
|
|
|
|
|
val = integer_one_node;
|
|
|
|
|
}
|
|
|
|
|
else if (code == EQ_EXPR)
|
|
|
|
|
{
|
|
|
|
|
if (max_lt || min_gt)
|
|
|
|
|
val = integer_zero_node;
|
|
|
|
|
}
|
|
|
|
|
else if (code == LT_EXPR)
|
|
|
|
|
{
|
|
|
|
|
if (max_lt)
|
|
|
|
|
val = integer_one_node;
|
|
|
|
|
if (!min_lt)
|
|
|
|
|
val = integer_zero_node;
|
|
|
|
|
}
|
|
|
|
|
else if (code == GT_EXPR)
|
|
|
|
|
{
|
|
|
|
|
if (min_gt)
|
|
|
|
|
val = integer_one_node;
|
|
|
|
|
if (!max_gt)
|
|
|
|
|
val = integer_zero_node;
|
|
|
|
|
}
|
|
|
|
|
else if (code == LE_EXPR)
|
|
|
|
|
{
|
|
|
|
|
if (!max_gt)
|
|
|
|
|
val = integer_one_node;
|
|
|
|
|
if (min_gt)
|
|
|
|
|
val = integer_zero_node;
|
|
|
|
|
}
|
|
|
|
|
else if (code == GE_EXPR)
|
|
|
|
|
{
|
|
|
|
|
if (!min_lt)
|
|
|
|
|
val = integer_one_node;
|
|
|
|
|
if (max_lt)
|
|
|
|
|
val = integer_zero_node;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* If primop0 was sign-extended and unsigned comparison specd,
|
|
|
|
|
we did a signed comparison above using the signed type bounds.
|
|
|
|
|
But the comparison we output must be unsigned.
|
|
|
|
|
|
|
|
|
|
Also, for inequalities, VAL is no good; but if the signed
|
|
|
|
|
comparison had *any* fixed result, it follows that the
|
|
|
|
|
unsigned comparison just tests the sign in reverse
|
|
|
|
|
(positive values are LE, negative ones GE).
|
|
|
|
|
So we can generate an unsigned comparison
|
|
|
|
|
against an extreme value of the signed type. */
|
|
|
|
|
|
|
|
|
|
if (unsignedp && !unsignedp0)
|
|
|
|
|
{
|
|
|
|
|
if (val != 0)
|
|
|
|
|
switch (code)
|
|
|
|
|
{
|
|
|
|
|
case LT_EXPR:
|
|
|
|
|
case GE_EXPR:
|
|
|
|
|
primop1 = TYPE_MIN_VALUE (type);
|
|
|
|
|
val = 0;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case LE_EXPR:
|
|
|
|
|
case GT_EXPR:
|
|
|
|
|
primop1 = TYPE_MAX_VALUE (type);
|
|
|
|
|
val = 0;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
type = unsigned_type (type);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!max_gt && !unsignedp0 && TREE_CODE (primop0) != INTEGER_CST)
|
|
|
|
|
{
|
|
|
|
|
/* This is the case of (char)x >?< 0x80, which people used to use
|
|
|
|
|
expecting old C compilers to change the 0x80 into -0x80. */
|
|
|
|
|
if (val == integer_zero_node)
|
|
|
|
|
warning ("comparison is always 0 due to limited range of data type");
|
|
|
|
|
if (val == integer_one_node)
|
|
|
|
|
warning ("comparison is always 1 due to limited range of data type");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!min_lt && unsignedp0 && TREE_CODE (primop0) != INTEGER_CST)
|
|
|
|
|
{
|
|
|
|
|
/* This is the case of (unsigned char)x >?< -1 or < 0. */
|
|
|
|
|
if (val == integer_zero_node)
|
|
|
|
|
warning ("comparison is always 0 due to limited range of data type");
|
|
|
|
|
if (val == integer_one_node)
|
|
|
|
|
warning ("comparison is always 1 due to limited range of data type");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (val != 0)
|
|
|
|
|
{
|
|
|
|
|
/* Don't forget to evaluate PRIMOP0 if it has side effects. */
|
|
|
|
|
if (TREE_SIDE_EFFECTS (primop0))
|
|
|
|
|
return build (COMPOUND_EXPR, TREE_TYPE (val), primop0, val);
|
|
|
|
|
return val;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Value is not predetermined, but do the comparison
|
|
|
|
|
in the type of the operand that is not constant.
|
|
|
|
|
TYPE is already properly set. */
|
|
|
|
|
}
|
|
|
|
|
else if (real1 && real2
|
|
|
|
|
&& (TYPE_PRECISION (TREE_TYPE (primop0))
|
|
|
|
|
== TYPE_PRECISION (TREE_TYPE (primop1))))
|
|
|
|
|
type = TREE_TYPE (primop0);
|
|
|
|
|
|
|
|
|
|
/* If args' natural types are both narrower than nominal type
|
|
|
|
|
and both extend in the same manner, compare them
|
|
|
|
|
in the type of the wider arg.
|
|
|
|
|
Otherwise must actually extend both to the nominal
|
|
|
|
|
common type lest different ways of extending
|
|
|
|
|
alter the result.
|
|
|
|
|
(eg, (short)-1 == (unsigned short)-1 should be 0.) */
|
|
|
|
|
|
|
|
|
|
else if (unsignedp0 == unsignedp1 && real1 == real2
|
|
|
|
|
&& TYPE_PRECISION (TREE_TYPE (primop0)) < TYPE_PRECISION (*restype_ptr)
|
|
|
|
|
&& TYPE_PRECISION (TREE_TYPE (primop1)) < TYPE_PRECISION (*restype_ptr))
|
|
|
|
|
{
|
|
|
|
|
type = common_type (TREE_TYPE (primop0), TREE_TYPE (primop1));
|
|
|
|
|
type = signed_or_unsigned_type (unsignedp0
|
|
|
|
|
|| TREE_UNSIGNED (*restype_ptr),
|
|
|
|
|
type);
|
|
|
|
|
/* Make sure shorter operand is extended the right way
|
|
|
|
|
to match the longer operand. */
|
|
|
|
|
primop0 = convert (signed_or_unsigned_type (unsignedp0, TREE_TYPE (primop0)),
|
|
|
|
|
primop0);
|
|
|
|
|
primop1 = convert (signed_or_unsigned_type (unsignedp1, TREE_TYPE (primop1)),
|
|
|
|
|
primop1);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
/* Here we must do the comparison on the nominal type
|
|
|
|
|
using the args exactly as we received them. */
|
|
|
|
|
type = *restype_ptr;
|
|
|
|
|
primop0 = op0;
|
|
|
|
|
primop1 = op1;
|
|
|
|
|
|
|
|
|
|
if (!real1 && !real2 && integer_zerop (primop1)
|
|
|
|
|
&& TREE_UNSIGNED (*restype_ptr))
|
|
|
|
|
{
|
|
|
|
|
tree value = 0;
|
|
|
|
|
switch (code)
|
|
|
|
|
{
|
|
|
|
|
case GE_EXPR:
|
----------------------------------
GCC-2.6.1 COMES TO FREEBSD-current
----------------------------------
Everybody needs to 'make world'.
Oakland, Nov 2nd 1994. In a surprise move this sunny afternoon, the release-
engineer for the slightly delayed FreeBSD-2.0, Poul-Henning Kamp (28),
decided to pull in the new version 2.6.1 of the GNU C-compiler.
The new version of the compiler was release today at noon, and hardly 9
hours later it was committed into the FreeBSD-current source-repository.
"It's is simply because we have had too much trouble with the version 2.6.0
of the compiler" Poul-Henning told the FreeBSD-Gazette, "we took a gamble
when we decided to use that as our compiler for the 2.0 release, but it
seems to pay of in the end now" he concludes.
The move has not been discussed on the "core" list at all, and will come as
a surprise for most Poul-Hennings peers. "I have only discussed it with
Jordan [J. K. Hubbard, the FreeBSD's resident humourist], and we agreed that
we needed to do it, so ... I did it!". After a breath he added with a grin:
"My email will probably get an all time 'disk-full' now!".
This will bring quite a flag-day to the FreeBSD developers, the patch-file
is almost 1.4 Megabyte, and they will have to run "make world" to get
entirely -current again. "Too bad, but we just had to do this." Was
the only comment from Poul-Henning to these problems.
When asked how this move would impact the 2.0 release-date, Poul-Hennings
face grew dark, he mumbled some very Danish words while he moved his fingers
in strange geometrical patterns. Immediately something ecclipsed the Sun, a
minor tremor shook the buildings, and the temperature fell significantly.
We decided not to pursure the question.
-----------
JOB-SECTION
-----------
Are you a dedicated GCC-hacker ?
We BADLY need somebody to look at the 'freebsd' OS in gcc, sanitize it and
carry the patches back to the GNU people. In particular, we need to get
out of the "i386-only" spot we are in now. I have the stuff to take a
gnu-dist into bmake-form, and will do that part.
Please apply to phk@freebsd.org
No Novice Need Apply.
1994-11-03 06:52:42 +00:00
|
|
|
|
/* All unsigned values are >= 0, so we warn if extra warnings
|
|
|
|
|
are requested. However, if OP0 is a constant that is
|
|
|
|
|
>= 0, the signedness of the comparison isn't an issue,
|
|
|
|
|
so suppress the warning. */
|
|
|
|
|
if (extra_warnings
|
|
|
|
|
&& ! (TREE_CODE (primop0) == INTEGER_CST
|
|
|
|
|
&& ! TREE_OVERFLOW (convert (signed_type (type),
|
|
|
|
|
primop0))))
|
1994-08-02 20:15:59 +00:00
|
|
|
|
warning ("unsigned value >= 0 is always 1");
|
|
|
|
|
value = integer_one_node;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case LT_EXPR:
|
----------------------------------
GCC-2.6.1 COMES TO FREEBSD-current
----------------------------------
Everybody needs to 'make world'.
Oakland, Nov 2nd 1994. In a surprise move this sunny afternoon, the release-
engineer for the slightly delayed FreeBSD-2.0, Poul-Henning Kamp (28),
decided to pull in the new version 2.6.1 of the GNU C-compiler.
The new version of the compiler was release today at noon, and hardly 9
hours later it was committed into the FreeBSD-current source-repository.
"It's is simply because we have had too much trouble with the version 2.6.0
of the compiler" Poul-Henning told the FreeBSD-Gazette, "we took a gamble
when we decided to use that as our compiler for the 2.0 release, but it
seems to pay of in the end now" he concludes.
The move has not been discussed on the "core" list at all, and will come as
a surprise for most Poul-Hennings peers. "I have only discussed it with
Jordan [J. K. Hubbard, the FreeBSD's resident humourist], and we agreed that
we needed to do it, so ... I did it!". After a breath he added with a grin:
"My email will probably get an all time 'disk-full' now!".
This will bring quite a flag-day to the FreeBSD developers, the patch-file
is almost 1.4 Megabyte, and they will have to run "make world" to get
entirely -current again. "Too bad, but we just had to do this." Was
the only comment from Poul-Henning to these problems.
When asked how this move would impact the 2.0 release-date, Poul-Hennings
face grew dark, he mumbled some very Danish words while he moved his fingers
in strange geometrical patterns. Immediately something ecclipsed the Sun, a
minor tremor shook the buildings, and the temperature fell significantly.
We decided not to pursure the question.
-----------
JOB-SECTION
-----------
Are you a dedicated GCC-hacker ?
We BADLY need somebody to look at the 'freebsd' OS in gcc, sanitize it and
carry the patches back to the GNU people. In particular, we need to get
out of the "i386-only" spot we are in now. I have the stuff to take a
gnu-dist into bmake-form, and will do that part.
Please apply to phk@freebsd.org
No Novice Need Apply.
1994-11-03 06:52:42 +00:00
|
|
|
|
if (extra_warnings
|
|
|
|
|
&& ! (TREE_CODE (primop0) == INTEGER_CST
|
|
|
|
|
&& ! TREE_OVERFLOW (convert (signed_type (type),
|
|
|
|
|
primop0))))
|
1994-08-02 20:15:59 +00:00
|
|
|
|
warning ("unsigned value < 0 is always 0");
|
|
|
|
|
value = integer_zero_node;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (value != 0)
|
|
|
|
|
{
|
|
|
|
|
/* 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 value;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
*op0_ptr = convert (type, primop0);
|
|
|
|
|
*op1_ptr = convert (type, primop1);
|
|
|
|
|
|
|
|
|
|
*restype_ptr = integer_type_node;
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Prepare expr to be an argument of a TRUTH_NOT_EXPR,
|
|
|
|
|
or validate its data type for an `if' or `while' statement or ?..: exp.
|
|
|
|
|
|
|
|
|
|
This preparation consists of taking the ordinary
|
|
|
|
|
representation of an expression expr and producing a valid tree
|
|
|
|
|
boolean expression describing whether expr is nonzero. We could
|
|
|
|
|
simply always do build_binary_op (NE_EXPR, expr, integer_zero_node, 1),
|
|
|
|
|
but we optimize comparisons, &&, ||, and !.
|
|
|
|
|
|
|
|
|
|
The resulting type should always be `integer_type_node'. */
|
|
|
|
|
|
|
|
|
|
tree
|
|
|
|
|
truthvalue_conversion (expr)
|
|
|
|
|
tree expr;
|
|
|
|
|
{
|
|
|
|
|
if (TREE_CODE (expr) == ERROR_MARK)
|
|
|
|
|
return expr;
|
|
|
|
|
|
|
|
|
|
#if 0 /* This appears to be wrong for C++. */
|
|
|
|
|
/* These really should return error_mark_node after 2.4 is stable.
|
|
|
|
|
But not all callers handle ERROR_MARK properly. */
|
|
|
|
|
switch (TREE_CODE (TREE_TYPE (expr)))
|
|
|
|
|
{
|
|
|
|
|
case RECORD_TYPE:
|
|
|
|
|
error ("struct type value used where scalar is required");
|
|
|
|
|
return integer_zero_node;
|
|
|
|
|
|
|
|
|
|
case UNION_TYPE:
|
|
|
|
|
error ("union type value used where scalar is required");
|
|
|
|
|
return integer_zero_node;
|
|
|
|
|
|
|
|
|
|
case ARRAY_TYPE:
|
|
|
|
|
error ("array type value used where scalar is required");
|
|
|
|
|
return integer_zero_node;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
#endif /* 0 */
|
|
|
|
|
|
|
|
|
|
switch (TREE_CODE (expr))
|
|
|
|
|
{
|
|
|
|
|
/* It is simpler and generates better code to have only TRUTH_*_EXPR
|
|
|
|
|
or comparison expressions as truth values at this level. */
|
|
|
|
|
#if 0
|
|
|
|
|
case COMPONENT_REF:
|
|
|
|
|
/* A one-bit unsigned bit-field is already acceptable. */
|
|
|
|
|
if (1 == TREE_INT_CST_LOW (DECL_SIZE (TREE_OPERAND (expr, 1)))
|
|
|
|
|
&& TREE_UNSIGNED (TREE_OPERAND (expr, 1)))
|
|
|
|
|
return expr;
|
|
|
|
|
break;
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
case EQ_EXPR:
|
|
|
|
|
/* It is simpler and generates better code to have only TRUTH_*_EXPR
|
|
|
|
|
or comparison expressions as truth values at this level. */
|
|
|
|
|
#if 0
|
|
|
|
|
if (integer_zerop (TREE_OPERAND (expr, 1)))
|
|
|
|
|
return build_unary_op (TRUTH_NOT_EXPR, TREE_OPERAND (expr, 0), 0);
|
|
|
|
|
#endif
|
|
|
|
|
case NE_EXPR: case LE_EXPR: case GE_EXPR: case LT_EXPR: case GT_EXPR:
|
|
|
|
|
case TRUTH_ANDIF_EXPR:
|
|
|
|
|
case TRUTH_ORIF_EXPR:
|
|
|
|
|
case TRUTH_AND_EXPR:
|
|
|
|
|
case TRUTH_OR_EXPR:
|
|
|
|
|
case TRUTH_XOR_EXPR:
|
|
|
|
|
return convert (integer_type_node, expr);
|
|
|
|
|
|
|
|
|
|
case ERROR_MARK:
|
|
|
|
|
return expr;
|
|
|
|
|
|
|
|
|
|
case INTEGER_CST:
|
|
|
|
|
return integer_zerop (expr) ? integer_zero_node : integer_one_node;
|
|
|
|
|
|
|
|
|
|
case REAL_CST:
|
|
|
|
|
return real_zerop (expr) ? integer_zero_node : integer_one_node;
|
|
|
|
|
|
|
|
|
|
case ADDR_EXPR:
|
|
|
|
|
if (TREE_SIDE_EFFECTS (TREE_OPERAND (expr, 0)))
|
|
|
|
|
return build (COMPOUND_EXPR, integer_type_node,
|
|
|
|
|
TREE_OPERAND (expr, 0), integer_one_node);
|
|
|
|
|
else
|
|
|
|
|
return integer_one_node;
|
|
|
|
|
|
|
|
|
|
case COMPLEX_EXPR:
|
|
|
|
|
return build_binary_op ((TREE_SIDE_EFFECTS (TREE_OPERAND (expr, 1))
|
|
|
|
|
? TRUTH_OR_EXPR : TRUTH_ORIF_EXPR),
|
|
|
|
|
truthvalue_conversion (TREE_OPERAND (expr, 0)),
|
|
|
|
|
truthvalue_conversion (TREE_OPERAND (expr, 1)),
|
|
|
|
|
0);
|
|
|
|
|
|
|
|
|
|
case NEGATE_EXPR:
|
|
|
|
|
case ABS_EXPR:
|
|
|
|
|
case FLOAT_EXPR:
|
|
|
|
|
case FFS_EXPR:
|
|
|
|
|
/* These don't change whether an object is non-zero or zero. */
|
|
|
|
|
return truthvalue_conversion (TREE_OPERAND (expr, 0));
|
|
|
|
|
|
|
|
|
|
case LROTATE_EXPR:
|
|
|
|
|
case RROTATE_EXPR:
|
|
|
|
|
/* These don't change whether an object is zero or non-zero, 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, integer_type_node, TREE_OPERAND (expr, 1),
|
|
|
|
|
truthvalue_conversion (TREE_OPERAND (expr, 0)));
|
|
|
|
|
else
|
|
|
|
|
return truthvalue_conversion (TREE_OPERAND (expr, 0));
|
1995-05-30 05:05:38 +00:00
|
|
|
|
|
1994-08-02 20:15:59 +00:00
|
|
|
|
case COND_EXPR:
|
|
|
|
|
/* Distribute the conversion into the arms of a COND_EXPR. */
|
|
|
|
|
return fold (build (COND_EXPR, integer_type_node, TREE_OPERAND (expr, 0),
|
|
|
|
|
truthvalue_conversion (TREE_OPERAND (expr, 1)),
|
|
|
|
|
truthvalue_conversion (TREE_OPERAND (expr, 2))));
|
|
|
|
|
|
|
|
|
|
case CONVERT_EXPR:
|
|
|
|
|
/* Don't cancel the effect of a CONVERT_EXPR from a REFERENCE_TYPE,
|
|
|
|
|
since that affects how `default_conversion' will behave. */
|
|
|
|
|
if (TREE_CODE (TREE_TYPE (expr)) == REFERENCE_TYPE
|
|
|
|
|
|| TREE_CODE (TREE_TYPE (TREE_OPERAND (expr, 0))) == REFERENCE_TYPE)
|
|
|
|
|
break;
|
|
|
|
|
/* fall through... */
|
|
|
|
|
case NOP_EXPR:
|
|
|
|
|
/* If this is widening the argument, we can ignore it. */
|
|
|
|
|
if (TYPE_PRECISION (TREE_TYPE (expr))
|
|
|
|
|
>= TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (expr, 0))))
|
|
|
|
|
return truthvalue_conversion (TREE_OPERAND (expr, 0));
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case MINUS_EXPR:
|
|
|
|
|
/* With IEEE arithmetic, x - x may not equal 0, so we can't optimize
|
|
|
|
|
this case. */
|
|
|
|
|
if (TARGET_FLOAT_FORMAT == IEEE_FLOAT_FORMAT
|
|
|
|
|
&& TREE_CODE (TREE_TYPE (expr)) == REAL_TYPE)
|
|
|
|
|
break;
|
|
|
|
|
/* fall through... */
|
|
|
|
|
case BIT_XOR_EXPR:
|
|
|
|
|
/* This and MINUS_EXPR can be changed into a comparison of the
|
|
|
|
|
two objects. */
|
|
|
|
|
if (TREE_TYPE (TREE_OPERAND (expr, 0))
|
|
|
|
|
== TREE_TYPE (TREE_OPERAND (expr, 1)))
|
|
|
|
|
return build_binary_op (NE_EXPR, TREE_OPERAND (expr, 0),
|
|
|
|
|
TREE_OPERAND (expr, 1), 1);
|
|
|
|
|
return build_binary_op (NE_EXPR, TREE_OPERAND (expr, 0),
|
|
|
|
|
fold (build1 (NOP_EXPR,
|
|
|
|
|
TREE_TYPE (TREE_OPERAND (expr, 0)),
|
|
|
|
|
TREE_OPERAND (expr, 1))), 1);
|
|
|
|
|
|
|
|
|
|
case BIT_AND_EXPR:
|
|
|
|
|
if (integer_onep (TREE_OPERAND (expr, 1)))
|
|
|
|
|
return expr;
|
|
|
|
|
|
|
|
|
|
case MODIFY_EXPR:
|
|
|
|
|
if (warn_parentheses && C_EXP_ORIGINAL_CODE (expr) == MODIFY_EXPR)
|
|
|
|
|
warning ("suggest parentheses around assignment used as truth value");
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (TREE_CODE (TREE_TYPE (expr)) == COMPLEX_TYPE)
|
|
|
|
|
return (build_binary_op
|
|
|
|
|
((TREE_SIDE_EFFECTS (expr)
|
|
|
|
|
? TRUTH_OR_EXPR : TRUTH_ORIF_EXPR),
|
|
|
|
|
truthvalue_conversion (build_unary_op (REALPART_EXPR, expr, 0)),
|
|
|
|
|
truthvalue_conversion (build_unary_op (IMAGPART_EXPR, expr, 0)),
|
|
|
|
|
0));
|
|
|
|
|
|
|
|
|
|
return build_binary_op (NE_EXPR, expr, integer_zero_node, 1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Read the rest of a #-directive from input stream FINPUT.
|
|
|
|
|
In normal use, the directive name and the white space after it
|
|
|
|
|
have already been read, so they won't be included in the result.
|
|
|
|
|
We allow for the fact that the directive line may contain
|
|
|
|
|
a newline embedded within a character or string literal which forms
|
|
|
|
|
a part of the directive.
|
|
|
|
|
|
|
|
|
|
The value is a string in a reusable buffer. It remains valid
|
|
|
|
|
only until the next time this function is called. */
|
|
|
|
|
|
|
|
|
|
char *
|
|
|
|
|
get_directive_line (finput)
|
|
|
|
|
register FILE *finput;
|
|
|
|
|
{
|
|
|
|
|
static char *directive_buffer = NULL;
|
|
|
|
|
static unsigned buffer_length = 0;
|
|
|
|
|
register char *p;
|
|
|
|
|
register char *buffer_limit;
|
|
|
|
|
register int looking_for = 0;
|
|
|
|
|
register int char_escaped = 0;
|
|
|
|
|
|
|
|
|
|
if (buffer_length == 0)
|
|
|
|
|
{
|
|
|
|
|
directive_buffer = (char *)xmalloc (128);
|
|
|
|
|
buffer_length = 128;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
buffer_limit = &directive_buffer[buffer_length];
|
|
|
|
|
|
|
|
|
|
for (p = directive_buffer; ; )
|
|
|
|
|
{
|
|
|
|
|
int c;
|
|
|
|
|
|
|
|
|
|
/* Make buffer bigger if it is full. */
|
|
|
|
|
if (p >= buffer_limit)
|
|
|
|
|
{
|
|
|
|
|
register unsigned bytes_used = (p - directive_buffer);
|
|
|
|
|
|
|
|
|
|
buffer_length *= 2;
|
|
|
|
|
directive_buffer
|
|
|
|
|
= (char *)xrealloc (directive_buffer, buffer_length);
|
|
|
|
|
p = &directive_buffer[bytes_used];
|
|
|
|
|
buffer_limit = &directive_buffer[buffer_length];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
c = getc (finput);
|
|
|
|
|
|
|
|
|
|
/* Discard initial whitespace. */
|
|
|
|
|
if ((c == ' ' || c == '\t') && p == directive_buffer)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
/* Detect the end of the directive. */
|
|
|
|
|
if (c == '\n' && looking_for == 0)
|
|
|
|
|
{
|
|
|
|
|
ungetc (c, finput);
|
|
|
|
|
c = '\0';
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
*p++ = c;
|
|
|
|
|
|
|
|
|
|
if (c == 0)
|
|
|
|
|
return directive_buffer;
|
|
|
|
|
|
|
|
|
|
/* Handle string and character constant syntax. */
|
|
|
|
|
if (looking_for)
|
|
|
|
|
{
|
|
|
|
|
if (looking_for == c && !char_escaped)
|
|
|
|
|
looking_for = 0; /* Found terminator... stop looking. */
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
if (c == '\'' || c == '"')
|
|
|
|
|
looking_for = c; /* Don't stop buffering until we see another
|
|
|
|
|
another one of these (or an EOF). */
|
|
|
|
|
|
|
|
|
|
/* Handle backslash. */
|
|
|
|
|
char_escaped = (c == '\\' && ! char_escaped);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Make a variant type in the proper way for C/C++, propagating qualifiers
|
|
|
|
|
down to the element type of an array. */
|
|
|
|
|
|
|
|
|
|
tree
|
|
|
|
|
c_build_type_variant (type, constp, volatilep)
|
|
|
|
|
tree type;
|
|
|
|
|
int constp, volatilep;
|
|
|
|
|
{
|
|
|
|
|
if (TREE_CODE (type) == ARRAY_TYPE)
|
|
|
|
|
{
|
|
|
|
|
tree real_main_variant = TYPE_MAIN_VARIANT (type);
|
|
|
|
|
|
|
|
|
|
push_obstacks (TYPE_OBSTACK (real_main_variant),
|
|
|
|
|
TYPE_OBSTACK (real_main_variant));
|
|
|
|
|
type = build_array_type (c_build_type_variant (TREE_TYPE (type),
|
|
|
|
|
constp, volatilep),
|
|
|
|
|
TYPE_DOMAIN (type));
|
|
|
|
|
|
|
|
|
|
/* TYPE must be on same obstack as REAL_MAIN_VARIANT. If not,
|
|
|
|
|
make a copy. (TYPE might have come from the hash table and
|
|
|
|
|
REAL_MAIN_VARIANT might be in some function's obstack.) */
|
|
|
|
|
|
|
|
|
|
if (TYPE_OBSTACK (type) != TYPE_OBSTACK (real_main_variant))
|
|
|
|
|
{
|
|
|
|
|
type = copy_node (type);
|
|
|
|
|
TYPE_POINTER_TO (type) = TYPE_REFERENCE_TO (type) = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TYPE_MAIN_VARIANT (type) = real_main_variant;
|
|
|
|
|
pop_obstacks ();
|
|
|
|
|
}
|
|
|
|
|
return build_type_variant (type, constp, volatilep);
|
|
|
|
|
}
|