#include "tree-iterator.h"
#include "tree-gimple.h"
+/* Places where an lvalue, or modifiable lvalue, may be required.
+ Used to select diagnostic messages in lvalue_or_else and
+ readonly_error. */
+enum lvalue_use {
+ lv_assign,
+ lv_increment,
+ lv_decrement,
+ lv_addressof,
+ lv_asm
+};
+
+/* The level of nesting inside "__alignof__". */
+int in_alignof;
+
+/* The level of nesting inside "sizeof". */
+int in_sizeof;
+
+/* The level of nesting inside "typeof". */
+int in_typeof;
/* Nonzero if we've already printed a "missing braces around initializer"
message within this initializer. */
static void set_nonincremental_init (void);
static void set_nonincremental_init_from_string (tree);
static tree find_init_member (tree);
-static int lvalue_or_else (tree, const char *);
+static int lvalue_or_else (tree, enum lvalue_use);
+static void readonly_error (tree, enum lvalue_use);
\f
/* Do `exp = require_complete_type (exp);' to make sure exp
does not have an incomplete type. (That includes void types.) */
if (value != 0 && (TREE_CODE (value) == VAR_DECL
|| TREE_CODE (value) == PARM_DECL))
- error ("`%s' has an incomplete type",
+ error ("%qs has an incomplete type",
IDENTIFIER_POINTER (DECL_NAME (value)));
else
{
return;
default:
- abort ();
+ gcc_unreachable ();
}
if (TREE_CODE (TYPE_NAME (type)) == IDENTIFIER_NODE)
- error ("invalid use of undefined type `%s %s'",
+ error ("invalid use of undefined type %<%s %s%>",
type_code_string, IDENTIFIER_POINTER (TYPE_NAME (type)));
else
/* If this type has a typedef-name, the TYPE_NAME is a TYPE_DECL. */
- error ("invalid use of incomplete typedef `%s'",
+ error ("invalid use of incomplete typedef %qs",
IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (type))));
}
}
if (code2 == ENUMERAL_TYPE && code1 == INTEGER_TYPE)
return t2;
- if (code1 != code2)
- abort ();
+ gcc_assert (code1 == code2);
switch (code1)
{
tree elt = composite_type (TREE_TYPE (t1), TREE_TYPE (t2));
/* We should not have any type quals on arrays at all. */
- if (TYPE_QUALS (t1) || TYPE_QUALS (t2))
- abort ();
+ gcc_assert (!TYPE_QUALS (t1) && !TYPE_QUALS (t2));
/* Save space: see if the result is identical to one of the args. */
if (elt == TREE_TYPE (t1) && TYPE_DOMAIN (t1))
if (t2 == error_mark_node)
return t1;
- if (TREE_CODE (t1) != POINTER_TYPE || TREE_CODE (t2) != POINTER_TYPE)
- abort ();
+ gcc_assert (TREE_CODE (t1) == POINTER_TYPE
+ && TREE_CODE (t2) == POINTER_TYPE);
/* Merge the attributes. */
attributes = targetm.merge_type_attributes (t1, t2);
code1 = TREE_CODE (t1);
code2 = TREE_CODE (t2);
- if (code1 != VECTOR_TYPE && code1 != COMPLEX_TYPE
- && code1 != REAL_TYPE && code1 != INTEGER_TYPE)
- abort ();
-
- if (code2 != VECTOR_TYPE && code2 != COMPLEX_TYPE
- && code2 != REAL_TYPE && code2 != INTEGER_TYPE)
- abort ();
+ gcc_assert (code1 == VECTOR_TYPE || code1 == COMPLEX_TYPE
+ || code1 == REAL_TYPE || code1 == INTEGER_TYPE);
+ gcc_assert (code2 == VECTOR_TYPE || code2 == COMPLEX_TYPE
+ || code2 == REAL_TYPE || code2 == INTEGER_TYPE);
/* If one type is a vector type, return that type. (How the usual
arithmetic conversions apply to the vector types extension is not
while (t1 && TREE_CODE (t1) != TRANSLATION_UNIT_DECL)
switch (TREE_CODE_CLASS (TREE_CODE (t1)))
{
- case 'd': t1 = DECL_CONTEXT (t1); break;
- case 't': t1 = TYPE_CONTEXT (t1); break;
- case 'x': t1 = BLOCK_SUPERCONTEXT (t1); break; /* assume block */
- default: abort ();
+ case tcc_declaration:
+ t1 = DECL_CONTEXT (t1); break;
+ case tcc_type:
+ t1 = TYPE_CONTEXT (t1); break;
+ case tcc_exceptional:
+ t1 = BLOCK_SUPERCONTEXT (t1); break; /* assume block */
+ default: gcc_unreachable ();
}
while (t2 && TREE_CODE (t2) != TRANSLATION_UNIT_DECL)
switch (TREE_CODE_CLASS (TREE_CODE (t2)))
{
- case 'd': t2 = DECL_CONTEXT (t2); break;
- case 't': t2 = TYPE_CONTEXT (t2); break;
- case 'x': t2 = BLOCK_SUPERCONTEXT (t2); break; /* assume block */
- default: abort ();
+ case tcc_declaration:
+ t2 = DECL_CONTEXT (t2); break;
+ case tcc_type:
+ t2 = TYPE_CONTEXT (t2); break;
+ case tcc_exceptional:
+ t2 = BLOCK_SUPERCONTEXT (t2); break; /* assume block */
+ default: gcc_unreachable ();
}
return t1 == t2;
}
default:
- abort ();
+ gcc_unreachable ();
}
}
/* 'volatile' qualifiers on a function's return type used to mean
the function is noreturn. */
if (TYPE_VOLATILE (ret1) != TYPE_VOLATILE (ret2))
- pedwarn ("function return types not compatible due to `volatile'");
+ pedwarn ("function return types not compatible due to %<volatile%>");
if (TYPE_VOLATILE (ret1))
ret1 = build_qualified_type (TYPE_MAIN_VARIANT (ret1),
TYPE_QUALS (ret1) & ~TYPE_QUAL_VOLATILE);
int volatilep = 0;
int lvalue_array_p;
- if (TREE_CODE_CLASS (TREE_CODE (exp)) == 'r' || DECL_P (exp))
+ if (REFERENCE_CLASS_P (exp) || DECL_P (exp))
{
constp = TREE_READONLY (exp);
volatilep = TREE_THIS_VOLATILE (exp);
if (!objc_is_public (datum, component))
return error_mark_node;
- /* If DATUM is a COMPOUND_EXPR, move our reference inside it.
- Ensure that the arguments are not lvalues; otherwise,
- if the component is an array, it would wrongly decay to a pointer in
- C89 mode.
- We cannot do this with a COND_EXPR, because in a conditional expression
- the default promotions are applied to both sides, and this would yield
- the wrong type of the result; for example, if the components have
- type "char". */
- switch (TREE_CODE (datum))
- {
- case COMPOUND_EXPR:
- {
- tree value = build_component_ref (TREE_OPERAND (datum, 1), component);
- return build2 (COMPOUND_EXPR, TREE_TYPE (value),
- TREE_OPERAND (datum, 0), non_lvalue (value));
- }
- default:
- break;
- }
-
/* See if there is a field or component with name COMPONENT. */
if (code == RECORD_TYPE || code == UNION_TYPE)
if (!field)
{
- error ("%s has no member named `%s'",
- code == RECORD_TYPE ? "structure" : "union",
+ error ("%qT has no member named %qs", type,
IDENTIFIER_POINTER (component));
return error_mark_node;
}
return ref;
}
else if (code != ERROR_MARK)
- error ("request for member `%s' in something not a structure or union",
+ error ("request for member %qs in something not a structure or union",
IDENTIFIER_POINTER (component));
return error_mark_node;
return error_mark_node;
}
if (VOID_TYPE_P (t) && skip_evaluation == 0)
- warning ("dereferencing `void *' pointer");
+ warning ("dereferencing %<void *%> pointer");
/* We *must* set TREE_READONLY when dereferencing a pointer to const,
so that we get the proper error message if the result is used
}
}
else if (TREE_CODE (pointer) != ERROR_MARK)
- error ("invalid type argument of `%s'", errorstring);
+ error ("invalid type argument of %qs", errorstring);
return error_mark_node;
}
must have done so deliberately. */
if (warn_char_subscripts
&& TYPE_MAIN_VARIANT (TREE_TYPE (index)) == char_type_node)
- warning ("array subscript has type `char'");
+ warning ("array subscript has type %<char%>");
/* Apply default promotions *after* noticing character types. */
index = default_conversion (index);
while (TREE_CODE (foo) == COMPONENT_REF)
foo = TREE_OPERAND (foo, 0);
if (TREE_CODE (foo) == VAR_DECL && C_DECL_REGISTER (foo))
- pedwarn ("ISO C forbids subscripting `register' array");
+ pedwarn ("ISO C forbids subscripting %<register%> array");
else if (! flag_isoc99 && ! lvalue_p (foo))
pedwarn ("ISO C90 forbids subscripting non-lvalue array");
}
if (warn_char_subscripts
&& TREE_CODE (TREE_TYPE (index)) == INTEGER_TYPE
&& TYPE_MAIN_VARIANT (TREE_TYPE (index)) == char_type_node)
- warning ("subscript has type `char'");
+ warning ("subscript has type %<char%>");
/* Put the integer in IND to simplify error checking. */
if (TREE_CODE (TREE_TYPE (ar)) == INTEGER_TYPE)
{
tree ref;
tree decl = lookup_name (id);
- tree objc_ivar = lookup_objc_ivar (id);
+ tree objc_ivar = objc_lookup_ivar (id);
if (decl && decl != error_mark_node)
{
ref = decl;
else if (decl != objc_ivar && !DECL_FILE_SCOPE_P (decl))
{
- warning ("local declaration of `%s' hides instance variable",
+ warning ("local declaration of %qs hides instance variable",
IDENTIFIER_POINTER (id));
ref = decl;
}
assemble_external (ref);
TREE_USED (ref) = 1;
+ if (TREE_CODE (ref) == FUNCTION_DECL && !in_alignof)
+ {
+ if (!in_sizeof && !in_typeof)
+ C_DECL_USED (ref) = 1;
+ else if (DECL_INITIAL (ref) == 0
+ && DECL_EXTERNAL (ref)
+ && !TREE_PUBLIC (ref))
+ record_maybe_used_decl (ref);
+ }
+
if (TREE_CODE (ref) == CONST_DECL)
{
ref = DECL_INITIAL (ref);
return ref;
}
+/* Record details of decls possibly used inside sizeof or typeof. */
+struct maybe_used_decl
+{
+ /* The decl. */
+ tree decl;
+ /* The level seen at (in_sizeof + in_typeof). */
+ int level;
+ /* The next one at this level or above, or NULL. */
+ struct maybe_used_decl *next;
+};
+
+static struct maybe_used_decl *maybe_used_decls;
+
+/* Record that DECL, an undefined static function reference seen
+ inside sizeof or typeof, might be used if the operand of sizeof is
+ a VLA type or the operand of typeof is a variably modified
+ type. */
+
+void
+record_maybe_used_decl (tree decl)
+{
+ struct maybe_used_decl *t = XOBNEW (&parser_obstack, struct maybe_used_decl);
+ t->decl = decl;
+ t->level = in_sizeof + in_typeof;
+ t->next = maybe_used_decls;
+ maybe_used_decls = t;
+}
+
+/* Pop the stack of decls possibly used inside sizeof or typeof. If
+ USED is false, just discard them. If it is true, mark them used
+ (if no longer inside sizeof or typeof) or move them to the next
+ level up (if still inside sizeof or typeof). */
+
+void
+pop_maybe_used (bool used)
+{
+ struct maybe_used_decl *p = maybe_used_decls;
+ int cur_level = in_sizeof + in_typeof;
+ while (p && p->level > cur_level)
+ {
+ if (used)
+ {
+ if (cur_level == 0)
+ C_DECL_USED (p->decl) = 1;
+ else
+ p->level = cur_level;
+ }
+ p = p->next;
+ }
+ if (!used || cur_level == 0)
+ maybe_used_decls = p;
+}
+
+/* Return the result of sizeof applied to EXPR. */
+
+struct c_expr
+c_expr_sizeof_expr (struct c_expr expr)
+{
+ struct c_expr ret;
+ if (expr.value == error_mark_node)
+ {
+ ret.value = error_mark_node;
+ ret.original_code = ERROR_MARK;
+ pop_maybe_used (false);
+ }
+ else
+ {
+ ret.value = c_sizeof (TREE_TYPE (expr.value));
+ ret.original_code = ERROR_MARK;
+ pop_maybe_used (C_TYPE_VARIABLE_SIZE (TREE_TYPE (expr.value)));
+ }
+ return ret;
+}
+
+/* Return the result of sizeof applied to T, a structure for the type
+ name passed to sizeof (rather than the type itself). */
+
+struct c_expr
+c_expr_sizeof_type (struct c_type_name *t)
+{
+ tree type;
+ struct c_expr ret;
+ type = groktypename (t);
+ ret.value = c_sizeof (type);
+ ret.original_code = ERROR_MARK;
+ pop_maybe_used (C_TYPE_VARIABLE_SIZE (type));
+ return ret;
+}
+
/* Build a function call to function FUNCTION with parameters PARAMS.
PARAMS is a list--a chain of TREE_LIST nodes--in which the
TREE_VALUE of each node is a parameter-expression.
if (!(TREE_CODE (fntype) == POINTER_TYPE
&& TREE_CODE (TREE_TYPE (fntype)) == FUNCTION_TYPE))
{
- error ("called object is not a function");
+ error ("called object %qE is not a function", function);
return error_mark_node;
}
if (type == void_type_node)
{
if (name)
- error ("too many arguments to function `%s'",
+ error ("too many arguments to function %qs",
IDENTIFIER_POINTER (name));
else
error ("too many arguments to function");
/* Warn if any argument is passed as `float',
since without a prototype it would be `double'. */
if (formal_prec == TYPE_PRECISION (float_type_node))
- warn_for_assignment ("%s as `float' rather than `double' due to prototype", (char *) 0, name, parmnum + 1);
+ warn_for_assignment ("%s as %<float%> rather than "
+ "%<double%> due to prototype",
+ (char *) 0, name, parmnum + 1);
}
/* Detect integer changing in width or signedness.
These warnings are only activated with
if (typetail != 0 && TREE_VALUE (typetail) != void_type_node)
{
if (name)
- error ("too few arguments to function `%s'",
+ error ("too few arguments to function %qs",
IDENTIFIER_POINTER (name));
else
error ("too few arguments to function");
|| code2 == PLUS_EXPR || code2 == MINUS_EXPR)
warning ("suggest parentheses around arithmetic in operand of |");
/* Check cases like x|y==z */
- if (TREE_CODE_CLASS (code1) == '<' || TREE_CODE_CLASS (code2) == '<')
+ if (TREE_CODE_CLASS (code1) == tcc_comparison
+ || TREE_CODE_CLASS (code2) == tcc_comparison)
warning ("suggest parentheses around comparison in operand of |");
}
|| code2 == PLUS_EXPR || code2 == MINUS_EXPR)
warning ("suggest parentheses around arithmetic in operand of ^");
/* Check cases like x^y==z */
- if (TREE_CODE_CLASS (code1) == '<' || TREE_CODE_CLASS (code2) == '<')
+ if (TREE_CODE_CLASS (code1) == tcc_comparison
+ || TREE_CODE_CLASS (code2) == tcc_comparison)
warning ("suggest parentheses around comparison in operand of ^");
}
|| code2 == PLUS_EXPR || code2 == MINUS_EXPR)
warning ("suggest parentheses around + or - in operand of &");
/* Check cases like x&y==z */
- if (TREE_CODE_CLASS (code1) == '<' || TREE_CODE_CLASS (code2) == '<')
+ if (TREE_CODE_CLASS (code1) == tcc_comparison
+ || TREE_CODE_CLASS (code2) == tcc_comparison)
warning ("suggest parentheses around comparison in operand of &");
}
/* Similarly, check for cases like 1<=i<=10 that are probably errors. */
- if (TREE_CODE_CLASS (code) == '<'
- && (TREE_CODE_CLASS (code1) == '<'
- || TREE_CODE_CLASS (code2) == '<'))
+ if (TREE_CODE_CLASS (code) == tcc_comparison
+ && (TREE_CODE_CLASS (code1) == tcc_comparison
+ || TREE_CODE_CLASS (code2) == tcc_comparison))
warning ("comparisons like X<=Y<=Z do not have their mathematical meaning");
}
if (pedantic || warn_pointer_arith)
{
if (TREE_CODE (target_type) == VOID_TYPE)
- pedwarn ("pointer of type `void *' used in subtraction");
+ pedwarn ("pointer of type %<void *%> used in subtraction");
if (TREE_CODE (target_type) == FUNCTION_TYPE)
pedwarn ("pointer to a function used in subtraction");
}
{
code = CONJ_EXPR;
if (pedantic)
- pedwarn ("ISO C does not support `~' for complex conjugation");
+ pedwarn ("ISO C does not support %<~%> for complex conjugation");
if (!noconvert)
arg = default_conversion (arg);
}
tree real, imag;
if (pedantic)
- pedwarn ("ISO C does not support `++' and `--' on complex types");
+ pedwarn ("ISO C does not support %<++%> and %<--%>"
+ " on complex types");
arg = stabilize_reference (arg);
real = build_unary_op (REALPART_EXPR, arg, 1);
/* Complain about anything else that is not a true lvalue. */
if (!lvalue_or_else (arg, ((code == PREINCREMENT_EXPR
|| code == POSTINCREMENT_EXPR)
- ? "invalid lvalue in increment"
- : "invalid lvalue in decrement")))
+ ? lv_increment
+ : lv_decrement)))
return error_mark_node;
/* Report a read-only lvalue. */
readonly_error (arg,
((code == PREINCREMENT_EXPR
|| code == POSTINCREMENT_EXPR)
- ? "increment" : "decrement"));
+ ? lv_increment : lv_decrement));
if (TREE_CODE (TREE_TYPE (arg)) == BOOLEAN_TYPE)
val = boolean_increment (code, arg);
/* Anything not already handled and not a true memory reference
or a non-lvalue array is an error. */
else if (typecode != FUNCTION_TYPE && !flag
- && !lvalue_or_else (arg, "invalid lvalue in unary `&'"))
+ && !lvalue_or_else (arg, lv_addressof))
return error_mark_node;
/* Ordinary case; arg is a COMPONENT_REF or a decl. */
to which the address will point. Note that you can't get a
restricted pointer by taking the address of something, so we
only have to deal with `const' and `volatile' here. */
- if ((DECL_P (arg) || TREE_CODE_CLASS (TREE_CODE (arg)) == 'r')
+ if ((DECL_P (arg) || REFERENCE_CLASS_P (arg))
&& (TREE_READONLY (arg) || TREE_THIS_VOLATILE (arg)))
argtype = c_build_type_variant (argtype,
TREE_READONLY (arg),
TREE_THIS_VOLATILE (arg));
- argtype = build_pointer_type (argtype);
-
if (!c_mark_addressable (arg))
return error_mark_node;
- {
- tree addr;
-
- if (TREE_CODE (arg) == COMPONENT_REF)
- {
- tree field = TREE_OPERAND (arg, 1);
+ if (TREE_CODE (arg) == COMPONENT_REF
+ && DECL_C_BIT_FIELD (TREE_OPERAND (arg, 1)))
+ {
+ error ("attempt to take address of bit-field structure member %qD",
+ TREE_OPERAND (arg, 1));
+ return error_mark_node;
+ }
- addr = build_unary_op (ADDR_EXPR, TREE_OPERAND (arg, 0), flag);
+ argtype = build_pointer_type (argtype);
- if (DECL_C_BIT_FIELD (field))
- {
- error ("attempt to take address of bit-field structure member `%s'",
- IDENTIFIER_POINTER (DECL_NAME (field)));
- return error_mark_node;
- }
+ /* ??? Cope with user tricks that amount to offsetof. Delete this
+ when we have proper support for integer constant expressions. */
+ val = get_base_address (arg);
+ if (val && TREE_CODE (val) == INDIRECT_REF
+ && integer_zerop (TREE_OPERAND (val, 0)))
+ return fold_convert (argtype, fold_offsetof (arg));
- addr = fold (build2 (PLUS_EXPR, argtype,
- convert (argtype, addr),
- convert (argtype, byte_position (field))));
- }
- else
- addr = build1 (code, argtype, arg);
+ val = build1 (ADDR_EXPR, argtype, arg);
- if (TREE_CODE (arg) == COMPOUND_LITERAL_EXPR)
- TREE_INVARIANT (addr) = TREE_CONSTANT (addr) = 1;
+ if (TREE_CODE (arg) == COMPOUND_LITERAL_EXPR)
+ TREE_INVARIANT (val) = TREE_CONSTANT (val) = 1;
- return addr;
- }
+ return val;
default:
break;
}
/* Return nonzero if REF is an lvalue valid for this language;
- otherwise, print an error message and return zero. */
+ otherwise, print an error message and return zero. USE says
+ how the lvalue is being used and so selects the error message. */
static int
-lvalue_or_else (tree ref, const char *msgid)
+lvalue_or_else (tree ref, enum lvalue_use use)
{
int win = lvalue_p (ref);
- if (! win)
- error ("%s", msgid);
+ if (!win)
+ {
+ switch (use)
+ {
+ case lv_assign:
+ error ("invalid lvalue in assignment");
+ break;
+ case lv_increment:
+ error ("invalid lvalue in increment");
+ break;
+ case lv_decrement:
+ error ("invalid lvalue in decrement");
+ break;
+ case lv_addressof:
+ error ("invalid lvalue in unary %<&%>");
+ break;
+ case lv_asm:
+ error ("invalid lvalue in asm statement");
+ break;
+ default:
+ gcc_unreachable ();
+ }
+ }
return win;
}
\f
-/* Warn about storing in something that is `const'. */
+/* Give an error for storing in something that is 'const'. */
-void
-readonly_error (tree arg, const char *msgid)
+static void
+readonly_error (tree arg, enum lvalue_use use)
{
+ gcc_assert (use == lv_assign || use == lv_increment || use == lv_decrement);
+ /* Using this macro rather than (for example) arrays of messages
+ ensures that all the format strings are checked at compile
+ time. */
+#define READONLY_MSG(A, I, D) (use == lv_assign \
+ ? (A) \
+ : (use == lv_increment ? (I) : (D)))
if (TREE_CODE (arg) == COMPONENT_REF)
{
if (TYPE_READONLY (TREE_TYPE (TREE_OPERAND (arg, 0))))
- readonly_error (TREE_OPERAND (arg, 0), msgid);
+ readonly_error (TREE_OPERAND (arg, 0), use);
else
- error ("%s of read-only member `%s'", _(msgid),
+ error (READONLY_MSG (N_("assignment of read-only member %qs"),
+ N_("increment of read-only member %qs"),
+ N_("decrement of read-only member %qs")),
IDENTIFIER_POINTER (DECL_NAME (TREE_OPERAND (arg, 1))));
}
else if (TREE_CODE (arg) == VAR_DECL)
- error ("%s of read-only variable `%s'", _(msgid),
+ error (READONLY_MSG (N_("assignment of read-only variable %qs"),
+ N_("increment of read-only variable %qs"),
+ N_("decrement of read-only variable %qs")),
IDENTIFIER_POINTER (DECL_NAME (arg)));
else
- error ("%s of read-only location", _(msgid));
+ error (READONLY_MSG (N_("assignment of read-only location"),
+ N_("increment of read-only location"),
+ N_("decrement of read-only location")));
}
\f
/* Mark EXP saying that we need to be able to take the
case COMPONENT_REF:
if (DECL_C_BIT_FIELD (TREE_OPERAND (x, 1)))
{
- error ("cannot take address of bit-field `%s'",
+ error ("cannot take address of bit-field %qs",
IDENTIFIER_POINTER (DECL_NAME (TREE_OPERAND (x, 1))));
return false;
}
{
if (TREE_PUBLIC (x) || TREE_STATIC (x) || DECL_EXTERNAL (x))
{
- error ("global register variable `%s' used in nested function",
+ error ("global register variable %qs used in nested function",
IDENTIFIER_POINTER (DECL_NAME (x)));
return false;
}
- pedwarn ("register variable `%s' used in nested function",
+ pedwarn ("register variable %qs used in nested function",
IDENTIFIER_POINTER (DECL_NAME (x)));
}
else if (C_DECL_REGISTER (x))
{
if (TREE_PUBLIC (x) || TREE_STATIC (x) || DECL_EXTERNAL (x))
{
- error ("address of global register variable `%s' requested",
+ error ("address of global register variable %qs requested",
IDENTIFIER_POINTER (DECL_NAME (x)));
return false;
}
- pedwarn ("address of register variable `%s' requested",
+ pedwarn ("address of register variable %qs requested",
IDENTIFIER_POINTER (DECL_NAME (x)));
}
else if (VOID_TYPE_P (TREE_TYPE (type1)))
{
if (pedantic && TREE_CODE (TREE_TYPE (type2)) == FUNCTION_TYPE)
- pedwarn ("ISO C forbids conditional expr between `void *' and function pointer");
+ pedwarn ("ISO C forbids conditional expr between "
+ "%<void *%> and function pointer");
result_type = build_pointer_type (qualify_type (TREE_TYPE (type1),
TREE_TYPE (type2)));
}
else if (VOID_TYPE_P (TREE_TYPE (type2)))
{
if (pedantic && TREE_CODE (TREE_TYPE (type1)) == FUNCTION_TYPE)
- pedwarn ("ISO C forbids conditional expr between `void *' and function pointer");
+ pedwarn ("ISO C forbids conditional expr between "
+ "%<void *%> and function pointer");
result_type = build_pointer_type (qualify_type (TREE_TYPE (type2),
TREE_TYPE (type1)));
}
/* The ObjC front-end uses TYPE_MAIN_VARIANT to tie together types differing
only in <protocol> qualifications. But when constructing cast expressions,
the protocols do matter and must be kept around. */
- if (!c_dialect_objc () || !objc_is_object_ptr (type))
- type = TYPE_MAIN_VARIANT (type);
+ if (objc_is_object_ptr (type) && objc_is_object_ptr (TREE_TYPE (expr)))
+ return build1 (NOP_EXPR, type, expr);
+
+ type = TYPE_MAIN_VARIANT (type);
if (TREE_CODE (type) == ARRAY_TYPE)
{
if (warn_bad_function_cast
&& TREE_CODE (value) == CALL_EXPR
&& TREE_CODE (type) != TREE_CODE (otype))
- warning ("cast does not match function type");
+ warning ("cast from function call of type %qT to non-matching "
+ "type %qT", otype, type);
if (TREE_CODE (type) == POINTER_TYPE
&& TREE_CODE (otype) == INTEGER_TYPE
/* Ignore any integer overflow caused by the cast. */
if (TREE_CODE (value) == INTEGER_CST)
{
- TREE_OVERFLOW (value) = TREE_OVERFLOW (ovalue);
-
- if (TREE_CODE_CLASS (TREE_CODE (ovalue)) == 'c')
+ if (EXPR_P (ovalue))
+ /* If OVALUE had overflow set, then so will VALUE, so it
+ is safe to overwrite. */
+ TREE_OVERFLOW (value) = TREE_OVERFLOW (ovalue);
+ else
+ TREE_OVERFLOW (value) = 0;
+
+ if (CONSTANT_CLASS_P (ovalue))
+ /* Similarly, constant_overflow cannot have become
+ cleared. */
TREE_CONSTANT_OVERFLOW (value) = TREE_CONSTANT_OVERFLOW (ovalue);
}
}
/* Interpret a cast of expression EXPR to type TYPE. */
tree
-c_cast_expr (tree type, tree expr)
+c_cast_expr (struct c_type_name *type_name, tree expr)
{
+ tree type;
int saved_wsp = warn_strict_prototypes;
/* This avoids warnings about unprototyped casts on
integers. E.g. "#define SIG_DFL (void(*)())0". */
if (TREE_CODE (expr) == INTEGER_CST)
warn_strict_prototypes = 0;
- type = groktypename (type);
+ type = groktypename (type_name);
warn_strict_prototypes = saved_wsp;
return build_c_cast (type, expr);
newrhs = build_binary_op (modifycode, lhs, rhs, 1);
}
- if (!lvalue_or_else (lhs, "invalid lvalue in assignment"))
+ if (!lvalue_or_else (lhs, lv_assign))
return error_mark_node;
- /* Warn about storing in something that is `const'. */
+ /* Give an error for storing in something that is 'const'. */
if (TREE_READONLY (lhs) || TYPE_READONLY (lhstype)
|| ((TREE_CODE (lhstype) == RECORD_TYPE
|| TREE_CODE (lhstype) == UNION_TYPE)
&& C_TYPE_FIELDS_READONLY (lhstype)))
- readonly_error (lhs, "assignment");
+ readonly_error (lhs, lv_assign);
/* If storing into a structure or union member,
it has probably been given type `int'.
if (TREE_CODE (newrhs) == ERROR_MARK)
return error_mark_node;
- /* Scan operands */
+ /* Scan operands. */
result = build2 (MODIFY_EXPR, lhstype, lhs, newrhs);
TREE_SIDE_EFFECTS (result) = 1;
return rhs;
}
/* Some types can interconvert without explicit casts. */
- else if (codel == VECTOR_TYPE
+ else if (codel == VECTOR_TYPE && coder == VECTOR_TYPE
&& vector_types_convertible_p (type, TREE_TYPE (rhs)))
return convert (type, rhs);
/* Arithmetic types all interconvert, and enum is treated like int. */
which are not ANSI null ptr constants. */
&& (!integer_zerop (rhs) || TREE_CODE (rhs) == NOP_EXPR)
&& TREE_CODE (ttl) == FUNCTION_TYPE)))
- warn_for_assignment ("ISO C forbids %s between function pointer and `void *'",
+ warn_for_assignment ("ISO C forbids %s between function "
+ "pointer and %<void *%>",
errtype, funname, parmnum);
/* Const and volatile mean something different for function types,
so the usual warnings are not appropriate. */
tree selector = objc_message_selector ();
if (selector && parmnum > 2)
- error ("incompatible type for argument %d of `%s'",
+ error ("incompatible type for argument %d of %qs",
parmnum - 2, IDENTIFIER_POINTER (selector));
else
- error ("incompatible type for argument %d of `%s'",
+ error ("incompatible type for argument %d of %qs",
parmnum, IDENTIFIER_POINTER (funname));
}
else
/* Print a warning using MSGID.
It gets OPNAME as its one parameter.
- if OPNAME is null and ARGNUM is 0, it is replaced by "passing arg of `FUNCTION'".
- Otherwise if OPNAME is null, it is replaced by "passing arg ARGNUM of `FUNCTION'".
+ If OPNAME is null, it is replaced by "passing arg ARGNUM of 'FUNCTION'".
FUNCTION and ARGNUM are handled specially if we are building an
Objective-C selector. */
function = selector;
argnum -= 2;
}
- if (argnum == 0)
- {
- if (function)
- {
- /* Function name is known; supply it. */
- const char *const argstring = _("passing arg of `%s'");
- new_opname = (char *) alloca (IDENTIFIER_LENGTH (function)
- + strlen (argstring) + 1 + 1);
- sprintf (new_opname, argstring,
- IDENTIFIER_POINTER (function));
- }
- else
- {
- /* Function name unknown (call through ptr). */
- const char *const argnofun = _("passing arg of pointer to function");
- new_opname = (char *) alloca (strlen (argnofun) + 1 + 1);
- sprintf (new_opname, argnofun);
- }
- }
- else if (function)
+ gcc_assert (argnum > 0);
+ if (function)
{
/* Function name is known; supply it. */
- const char *const argstring = _("passing arg %d of `%s'");
+ const char *const argstring = _("passing arg %d of '%s'");
new_opname = (char *) alloca (IDENTIFIER_LENGTH (function)
+ strlen (argstring) + 1 + 25 /*%d*/ + 1);
sprintf (new_opname, argstring, argnum,
return valid_compound_expr_initializer (TREE_OPERAND (value, 1),
endtype);
}
- else if (! TREE_CONSTANT (value)
- && ! initializer_constant_valid_p (value, endtype))
+ else if (!initializer_constant_valid_p (value, endtype))
return error_mark_node;
else
return value;
error ("%s", _(msgid));
ofwhat = print_spelling ((char *) alloca (spelling_length () + 1));
if (*ofwhat)
- error ("(near initialization for `%s')", ofwhat);
+ error ("(near initialization for %qs)", ofwhat);
}
/* Issue a pedantic warning for a bad initializer component.
pedwarn ("%s", _(msgid));
ofwhat = print_spelling ((char *) alloca (spelling_length () + 1));
if (*ofwhat)
- pedwarn ("(near initialization for `%s')", ofwhat);
+ pedwarn ("(near initialization for %qs)", ofwhat);
}
/* Issue a warning for a bad initializer component.
warning ("%s", _(msgid));
ofwhat = print_spelling ((char *) alloca (spelling_length () + 1));
if (*ofwhat)
- warning ("(near initialization for `%s')", ofwhat);
+ warning ("(near initialization for %qs)", ofwhat);
}
\f
/* If TYPE is an array type and EXPR is a parenthesized string
vector constructor is not constant (e.g. {1,2,3,foo()}) then punt
below and handle as a constructor. */
if (code == VECTOR_TYPE
+ && TREE_CODE (TREE_TYPE (inside_init)) == VECTOR_TYPE
&& vector_types_convertible_p (TREE_TYPE (inside_init), type)
&& TREE_CONSTANT (inside_init))
{
inside_init = error_mark_node;
}
else if (require_constant
- && (!TREE_CONSTANT (inside_init)
- /* This test catches things like `7 / 0' which
- result in an expression for which TREE_CONSTANT
- is true, but which is not actually something
- that is a legal constant. We really should not
- be using this function, because it is a part of
- the back-end. Instead, the expression should
- already have been turned into ERROR_MARK_NODE. */
- || !initializer_constant_valid_p (inside_init,
- TREE_TYPE (inside_init))))
+ && !initializer_constant_valid_p (inside_init,
+ TREE_TYPE (inside_init)))
{
error_init ("initializer element is not constant");
inside_init = error_mark_node;
= convert_for_assignment (type, init, _("initialization"),
NULL_TREE, NULL_TREE, 0);
- if (require_constant && ! TREE_CONSTANT (inside_init))
+ /* Check to see if we have already given an error message. */
+ if (inside_init == error_mark_node)
+ ;
+ else if (require_constant && ! TREE_CONSTANT (inside_init))
{
error_init ("initializer element is not constant");
inside_init = error_mark_node;
}
else if (require_constant
- && initializer_constant_valid_p (inside_init, TREE_TYPE (inside_init)) == 0)
+ && !initializer_constant_valid_p (inside_init,
+ TREE_TYPE (inside_init)))
{
error_init ("initializer element is not computable at load time");
inside_init = error_mark_node;
such as (struct foo) {...}. */
static tree constructor_decl;
-/* start_init saves the ASMSPEC arg here for really_start_incremental_init. */
-static const char *constructor_asmspec;
-
/* Nonzero if this is an initializer for a top-level decl. */
static int constructor_top_level;
{
struct initializer_stack *next;
tree decl;
- const char *asmspec;
struct constructor_stack *constructor_stack;
struct constructor_range_stack *constructor_range_stack;
tree elements;
/* Prepare to parse and output the initializer for variable DECL. */
void
-start_init (tree decl, tree asmspec_tree, int top_level)
+start_init (tree decl, tree asmspec_tree ATTRIBUTE_UNUSED, int top_level)
{
const char *locus;
- struct initializer_stack *p = XNEW (struct initializer_stack);
- const char *asmspec = 0;
-
- if (asmspec_tree)
- asmspec = TREE_STRING_POINTER (asmspec_tree);
+ struct initializer_stack *p = xmalloc (sizeof (struct initializer_stack));
p->decl = constructor_decl;
- p->asmspec = constructor_asmspec;
p->require_constant_value = require_constant_value;
p->require_constant_elements = require_constant_elements;
p->constructor_stack = constructor_stack;
initializer_stack = p;
constructor_decl = decl;
- constructor_asmspec = asmspec;
constructor_designated = 0;
constructor_top_level = top_level;
free (q);
}
- if (constructor_range_stack)
- abort ();
+ gcc_assert (!constructor_range_stack);
/* Pop back to the data of the outer initializer (if any). */
free (spelling_base);
constructor_decl = p->decl;
- constructor_asmspec = p->asmspec;
require_constant_value = p->require_constant_value;
require_constant_elements = p->require_constant_elements;
constructor_stack = p->constructor_stack;
/* Detect non-empty initializations of zero-length arrays. */
if (constructor_max_index == NULL_TREE
&& TYPE_SIZE (constructor_type))
- constructor_max_index = build_int_cst (NULL_TREE, -1, -1);
+ constructor_max_index = build_int_cst (NULL_TREE, -1);
/* constructor_max_index needs to be an INTEGER_CST. Attempts
to initialize VLAs will cause a proper error; avoid tree
checking errors as well by setting a safe value. */
if (constructor_max_index
&& TREE_CODE (constructor_max_index) != INTEGER_CST)
- constructor_max_index = build_int_cst (NULL_TREE, -1, -1);
+ constructor_max_index = build_int_cst (NULL_TREE, -1);
constructor_index
= convert (bitsizetype,
{
/* Vectors are like simple fixed-size arrays. */
constructor_max_index =
- build_int_cst (NULL_TREE,
- TYPE_VECTOR_SUBPARTS (constructor_type) - 1, 0);
+ build_int_cst (NULL_TREE, TYPE_VECTOR_SUBPARTS (constructor_type) - 1);
constructor_index = convert (bitsizetype, bitsize_zero_node);
constructor_unfilled_index = constructor_index;
}
{
/* Vectors are like simple fixed-size arrays. */
constructor_max_index =
- build_int_cst (NULL_TREE,
- TYPE_VECTOR_SUBPARTS (constructor_type) - 1, 0);
+ build_int_cst (NULL_TREE, TYPE_VECTOR_SUBPARTS (constructor_type) - 1);
constructor_index = convert (bitsizetype, integer_zero_node);
constructor_unfilled_index = constructor_index;
}
/* Detect non-empty initializations of zero-length arrays. */
if (constructor_max_index == NULL_TREE
&& TYPE_SIZE (constructor_type))
- constructor_max_index = build_int_cst (NULL_TREE, -1, -1);
+ constructor_max_index = build_int_cst (NULL_TREE, -1);
/* constructor_max_index needs to be an INTEGER_CST. Attempts
to initialize VLAs will cause a proper error; avoid tree
checking errors as well by setting a safe value. */
if (constructor_max_index
&& TREE_CODE (constructor_max_index) != INTEGER_CST)
- constructor_max_index = build_int_cst (NULL_TREE, -1, -1);
+ constructor_max_index = build_int_cst (NULL_TREE, -1);
constructor_index
= convert (bitsizetype,
while (constructor_stack->implicit)
process_init_element (pop_init_level (1));
- if (constructor_range_stack)
- abort ();
+ gcc_assert (!constructor_range_stack);
}
/* Now output all pending elements. */
already have pedwarned for empty brackets. */
if (integer_zerop (constructor_unfilled_index))
constructor_type = NULL_TREE;
- else if (! TYPE_SIZE (constructor_type))
+ else
{
+ gcc_assert (!TYPE_SIZE (constructor_type));
+
if (constructor_depth > 2)
error_init ("initialization of flexible array member in a nested context");
else if (pedantic)
if (TREE_CHAIN (constructor_fields) != NULL_TREE)
constructor_type = NULL_TREE;
}
- else
- /* Zero-length arrays are no longer special, so we should no longer
- get here. */
- abort ();
}
/* Warn when some struct elements are implicitly initialized to zero. */
if (constructor_type == 0)
return 1;
- /* If there were errors in this designator list already, bail out silently. */
+ /* If there were errors in this designator list already, bail out
+ silently. */
if (designator_errorneous)
return 1;
if (!designator_depth)
{
- if (constructor_range_stack)
- abort ();
+ gcc_assert (!constructor_range_stack);
/* Designator list starts at the level of closest explicit
braces. */
return 1;
}
- if (TREE_CODE (constructor_type) == RECORD_TYPE
- || TREE_CODE (constructor_type) == UNION_TYPE)
+ switch (TREE_CODE (constructor_type))
{
+ case RECORD_TYPE:
+ case UNION_TYPE:
subtype = TREE_TYPE (constructor_fields);
if (subtype != error_mark_node)
subtype = TYPE_MAIN_VARIANT (subtype);
- }
- else if (TREE_CODE (constructor_type) == ARRAY_TYPE)
- {
+ break;
+ case ARRAY_TYPE:
subtype = TYPE_MAIN_VARIANT (TREE_TYPE (constructor_type));
+ break;
+ default:
+ gcc_unreachable ();
}
- else
- abort ();
subcode = TREE_CODE (subtype);
if (array && subcode != ARRAY_TYPE)
}
if (tail == 0)
- error ("unknown field `%s' specified in initializer",
+ error ("unknown field %qs specified in initializer",
IDENTIFIER_POINTER (fieldname));
else
{
const char *p, *end;
int byte, wchar_bytes, charwidth, bitpos;
- if (TREE_CODE (constructor_type) != ARRAY_TYPE)
- abort ();
+ gcc_assert (TREE_CODE (constructor_type) == ARRAY_TYPE);
if (TYPE_PRECISION (TREE_TYPE (TREE_TYPE (str)))
== TYPE_PRECISION (char_type_node))
wchar_bytes = 1;
- else if (TYPE_PRECISION (TREE_TYPE (TREE_TYPE (str)))
- == TYPE_PRECISION (wchar_type_node))
- wchar_bytes = TYPE_PRECISION (wchar_type_node) / BITS_PER_UNIT;
else
- abort ();
-
+ {
+ gcc_assert (TYPE_PRECISION (TREE_TYPE (TREE_TYPE (str)))
+ == TYPE_PRECISION (wchar_type_node));
+ wchar_bytes = TYPE_PRECISION (wchar_type_node) / BITS_PER_UNIT;
+ }
charwidth = TYPE_PRECISION (char_type_node);
type = TREE_TYPE (constructor_type);
p = TREE_STRING_POINTER (str);
<< (bitpos - HOST_BITS_PER_WIDE_INT);
}
- value = build_int_cst (type, val[1], val[0]);
+ value = build_int_cst_wide (type, val[1], val[0]);
add_pending_init (purpose, value);
}
constructor_erroneous = 1;
else if (!TREE_CONSTANT (value))
constructor_constant = 0;
- else if (initializer_constant_valid_p (value, TREE_TYPE (value)) == 0
+ else if (!initializer_constant_valid_p (value, TREE_TYPE (value))
|| ((TREE_CODE (constructor_type) == RECORD_TYPE
|| TREE_CODE (constructor_type) == UNION_TYPE)
&& DECL_C_BIT_FIELD (field)
&& TREE_CODE (value) != INTEGER_CST))
constructor_simple = 0;
- if (require_constant_value && ! TREE_CONSTANT (value))
+ if (!initializer_constant_valid_p (value, TREE_TYPE (value)))
{
- error_init ("initializer element is not constant");
- value = error_mark_node;
+ if (require_constant_value)
+ {
+ error_init ("initializer element is not constant");
+ value = error_mark_node;
+ }
+ else if (require_constant_elements)
+ pedwarn ("initializer element is not computable at load time");
}
- else if (require_constant_elements
- && initializer_constant_valid_p (value, TREE_TYPE (value)) == 0)
- pedwarn ("initializer element is not computable at load time");
/* If this field is empty (and not at the end of structure),
don't do anything other than checking the initializer. */
constructor_range_stack = 0;
while (constructor_stack != range_stack->stack)
{
- if (!constructor_stack->implicit)
- abort ();
+ gcc_assert (constructor_stack->implicit);
process_init_element (pop_init_level (1));
}
for (p = range_stack;
!p->range_end || tree_int_cst_equal (p->index, p->range_end);
p = p->prev)
{
- if (!constructor_stack->implicit)
- abort ();
+ gcc_assert (constructor_stack->implicit);
process_init_element (pop_init_level (1));
}
tree output = TREE_VALUE (tail);
STRIP_NOPS (output);
TREE_VALUE (tail) = output;
- lvalue_or_else (output, "invalid lvalue in asm statement");
+ lvalue_or_else (output, lv_asm);
constraint = TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (tail)));
c_finish_goto_ptr (tree expr)
{
if (pedantic)
- pedwarn ("ISO C forbids `goto *expr;'");
+ pedwarn ("ISO C forbids %<goto *expr;%>");
expr = convert (ptr_type_node, expr);
return add_stmt (build1 (GOTO_EXPR, void_type_node, expr));
}
tree valtype = TREE_TYPE (TREE_TYPE (current_function_decl));
if (TREE_THIS_VOLATILE (current_function_decl))
- warning ("function declared `noreturn' has a `return' statement");
+ warning ("function declared %<noreturn%> has a %<return%> statement");
if (!retval)
{
current_function_returns_null = 1;
if ((warn_return_type || flag_isoc99)
&& valtype != 0 && TREE_CODE (valtype) != VOID_TYPE)
- pedwarn_c99 ("`return' with no value, in function returning non-void");
+ pedwarn_c99 ("%<return%> with no value, in "
+ "function returning non-void");
}
else if (valtype == 0 || TREE_CODE (valtype) == VOID_TYPE)
{
current_function_returns_null = 1;
if (pedantic || TREE_CODE (TREE_TYPE (retval)) != VOID_TYPE)
- pedwarn ("`return' with a value, in function returning void");
+ pedwarn ("%<return%> with a value, in function returning void");
}
else
{
case ADDR_EXPR:
inner = TREE_OPERAND (inner, 0);
- while (TREE_CODE_CLASS (TREE_CODE (inner)) == 'r')
+ while (REFERENCE_CLASS_P (inner)
+ && TREE_CODE (inner) != INDIRECT_REF)
inner = TREE_OPERAND (inner, 0);
if (DECL_P (inner)
/* The SWITCH_STMT being built. */
tree switch_stmt;
- /* The original type of the testing expression, ie. before the
+ /* The original type of the testing expression, i.e. before the
default conversion is applied. */
tree orig_type;
if (warn_traditional && !in_system_header
&& (type == long_integer_type_node
|| type == long_unsigned_type_node))
- warning ("`long' switch expression not converted to `int' in ISO C");
+ warning ("%<long%> switch expression not converted to "
+ "%<int%> in ISO C");
exp = default_conversion (exp);
type = TREE_TYPE (exp);
else if (low_value)
error ("case label not within a switch statement");
else
- error ("`default' label not within a switch statement");
+ error ("%<default%> label not within a switch statement");
return label;
}
inner_if = TREE_OPERAND (inner_if, 0);
break;
default:
- abort ();
+ gcc_unreachable ();
}
found:
if (COND_EXPR_ELSE (inner_if))
- warning ("%Hsuggest explicit braces to avoid ambiguous `else'",
+ warning ("%Hsuggest explicit braces to avoid ambiguous %<else%>",
&if_locus);
}
/* If the expression is not of a type to which we cannot assign a line
number, wrap the thing in a no-op NOP_EXPR. */
- if (DECL_P (expr) || TREE_CODE_CLASS (TREE_CODE (expr)) == 'c')
+ if (DECL_P (expr) || CONSTANT_CLASS_P (expr))
expr = build1 (NOP_EXPR, TREE_TYPE (expr), expr);
if (EXPR_P (expr))
whose value is 0 but which isn't a valid null ptr const. */
if (pedantic && (!integer_zerop (op0) || op0 != orig_op0)
&& TREE_CODE (tt1) == FUNCTION_TYPE)
- pedwarn ("ISO C forbids comparison of `void *' with function pointer");
+ pedwarn ("ISO C forbids comparison of %<void *%>"
+ " with function pointer");
}
else if (VOID_TYPE_P (tt1))
{
if (pedantic && (!integer_zerop (op1) || op1 != orig_op1)
&& TREE_CODE (tt0) == FUNCTION_TYPE)
- pedwarn ("ISO C forbids comparison of `void *' with function pointer");
+ pedwarn ("ISO C forbids comparison of %<void *%>"
+ " with function pointer");
}
else
pedwarn ("comparison of distinct pointer types lacks a cast");
op0 = convert (result_type, op0);
if (TREE_TYPE (op1) != result_type)
op1 = convert (result_type, op1);
+
+ /* This can happen if one operand has a vector type, and the other
+ has a different type. */
+ if (TREE_CODE (op0) == ERROR_MARK || TREE_CODE (op1) == ERROR_MARK)
+ return error_mark_node;
}
if (build_type == NULL_TREE)
return result;
}
}
-
-/* Build the result of __builtin_offsetof. TYPE is the first argument to
- offsetof, i.e. a type. LIST is a tree_list that encodes component and
- array references; PURPOSE is set for the former and VALUE is set for
- the later. */
-
-tree
-build_offsetof (tree type, tree list)
-{
- tree t;
-
- /* Build "*(type *)0". */
- t = convert (build_pointer_type (type), null_pointer_node);
- t = build_indirect_ref (t, "");
-
- /* Build COMPONENT and ARRAY_REF expressions as needed. */
- for (list = nreverse (list); list ; list = TREE_CHAIN (list))
- if (TREE_PURPOSE (list))
- t = build_component_ref (t, TREE_PURPOSE (list));
- else
- t = build_array_ref (t, TREE_VALUE (list));
-
- /* Finalize the offsetof expression. For now all we need to do is take
- the address of the expression we created, and cast that to an integer
- type; this mirrors the traditional macro implementation of offsetof. */
- t = build_unary_op (ADDR_EXPR, t, 0);
- return convert (size_type_node, t);
-}