📄 c-typeck.c
字号:
/* See if there is a field or component with name COMPONENT. */ if (code == RECORD_TYPE || code == UNION_TYPE) { tree indirect = 0; if (TYPE_SIZE (type) == 0) { incomplete_type_error (NULL_TREE, type); return error_mark_node; } field = lookup_field (type, component, &indirect); if (!field) { error (code == RECORD_TYPE ? "structure has no member named `%s'" : "union has no member named `%s'", IDENTIFIER_POINTER (component)); return error_mark_node; } if (TREE_TYPE (field) == error_mark_node) return error_mark_node; /* If FIELD was found buried within an anonymous union, make one COMPONENT_REF to get that anonymous union, then fall thru to make a second COMPONENT_REF to get FIELD. */ if (indirect != 0) { ref = build (COMPONENT_REF, TREE_TYPE (indirect), datum, indirect); if (TREE_READONLY (datum) || TREE_READONLY (indirect)) TREE_READONLY (ref) = 1; if (TREE_THIS_VOLATILE (datum) || TREE_THIS_VOLATILE (indirect)) TREE_THIS_VOLATILE (ref) = 1; datum = ref; } ref = build (COMPONENT_REF, TREE_TYPE (field), datum, field); if (TREE_READONLY (datum) || TREE_READONLY (field)) TREE_READONLY (ref) = 1; if (TREE_THIS_VOLATILE (datum) || TREE_THIS_VOLATILE (field)) TREE_THIS_VOLATILE (ref) = 1; return ref; } else if (code != ERROR_MARK) error ("request for member `%s' in something not a structure or union", IDENTIFIER_POINTER (component)); return error_mark_node;}/* Given an expression PTR for a pointer, return an expression for the value pointed to. ERRORSTRING is the name of the operator to appear in error messages. */treebuild_indirect_ref (ptr, errorstring) tree ptr; char *errorstring;{ register tree pointer = default_conversion (ptr); register tree type = TREE_TYPE (pointer); if (TREE_CODE (type) == POINTER_TYPE) { if (TREE_CODE (pointer) == ADDR_EXPR && !flag_volatile && (TREE_TYPE (TREE_OPERAND (pointer, 0)) == TREE_TYPE (type))) return TREE_OPERAND (pointer, 0); else { tree t = TREE_TYPE (type); register tree ref = build1 (INDIRECT_REF, TYPE_MAIN_VARIANT (t), pointer); if (TYPE_SIZE (t) == 0 && TREE_CODE (t) != ARRAY_TYPE) { error ("dereferencing pointer to incomplete type"); return error_mark_node; } if (TREE_CODE (t) == VOID_TYPE) 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 to assign to. Also, &* is supposed to be a no-op. And ANSI C seems to specify that the type of the result should be the const type. */ /* A de-reference of a pointer to const is not a const. It is valid to change it via some other pointer. */ TREE_READONLY (ref) = TYPE_READONLY (t); TREE_SIDE_EFFECTS (ref) = TYPE_VOLATILE (t) || TREE_SIDE_EFFECTS (pointer) || flag_volatile; TREE_THIS_VOLATILE (ref) = TYPE_VOLATILE (t); return ref; } } else if (TREE_CODE (pointer) != ERROR_MARK) error ("invalid type argument of `%s'", errorstring); return error_mark_node;}/* This handles expressions of the form "a[i]", which denotes an array reference. This is logically equivalent in C to *(a+i), but we may do it differently. If A is a variable or a member, we generate a primitive ARRAY_REF. This avoids forcing the array out of registers, and can work on arrays that are not lvalues (for example, members of structures returned by functions). */treebuild_array_ref (array, index) tree array, index;{ if (index == 0) { error ("subscript missing in array reference"); return error_mark_node; } if (TREE_TYPE (array) == error_mark_node || TREE_TYPE (index) == error_mark_node) return error_mark_node; if (TREE_CODE (TREE_TYPE (array)) == ARRAY_TYPE && TREE_CODE (array) != INDIRECT_REF) { tree rval, type; /* Subscripting with type char is likely to lose on a machine where chars are signed. So warn on any machine, but optionally. Don't warn for unsigned char since that type is safe. Don't warn for signed char because anyone who uses that must have done so deliberately. */ if (warn_char_subscripts && TYPE_MAIN_VARIANT (TREE_TYPE (index)) == char_type_node) warning ("array subscript has type `char'"); /* Apply default promotions *after* noticing character types. */ index = default_conversion (index); /* Require integer *after* promotion, for sake of enums. */ if (TREE_CODE (TREE_TYPE (index)) != INTEGER_TYPE) { error ("array subscript is not an integer"); return error_mark_node; } /* An array that is indexed by a non-constant cannot be stored in a register; we must be able to do address arithmetic on its address. Likewise an array of elements of variable size. */ if (TREE_CODE (index) != INTEGER_CST || (TYPE_SIZE (TREE_TYPE (TREE_TYPE (array))) != 0 && TREE_CODE (TYPE_SIZE (TREE_TYPE (TREE_TYPE (array)))) != INTEGER_CST)) { if (mark_addressable (array) == 0) return error_mark_node; } /* An array that is indexed by a constant value which is not within the array bounds cannot be stored in a register either; because we would get a crash in store_bit_field/extract_bit_field when trying to access a non-existent part of the register. */ if (TREE_CODE (index) == INTEGER_CST && TYPE_VALUES (TREE_TYPE (array)) && ! int_fits_type_p (index, TYPE_VALUES (TREE_TYPE (array)))) { if (mark_addressable (array) == 0) return error_mark_node; } if (pedantic && !lvalue_p (array)) { if (DECL_REGISTER (array)) pedwarn ("ANSI C forbids subscripting `register' array"); else pedwarn ("ANSI C forbids subscripting non-lvalue array"); } if (pedantic) { tree foo = array; while (TREE_CODE (foo) == COMPONENT_REF) foo = TREE_OPERAND (foo, 0); if (TREE_CODE (foo) == VAR_DECL && DECL_REGISTER (foo)) pedwarn ("ANSI C forbids subscripting non-lvalue array"); } type = TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (array))); rval = build (ARRAY_REF, type, array, index); /* Array ref is const/volatile if the array elements are or if the array is. */ TREE_READONLY (rval) |= (TYPE_READONLY (TREE_TYPE (TREE_TYPE (array))) | TREE_READONLY (array)); TREE_SIDE_EFFECTS (rval) |= (TYPE_VOLATILE (TREE_TYPE (TREE_TYPE (array))) | TREE_SIDE_EFFECTS (array)); TREE_THIS_VOLATILE (rval) |= (TYPE_VOLATILE (TREE_TYPE (TREE_TYPE (array))) /* This was added by rms on 16 Nov 91. It fixes vol struct foo *a; a->elts[1] in an inline function. Hope it doesn't break something else. */ | TREE_THIS_VOLATILE (array)); return require_complete_type (fold (rval)); } { tree ar = default_conversion (array); tree ind = default_conversion (index); /* Put the integer in IND to simplify error checking. */ if (TREE_CODE (TREE_TYPE (ar)) == INTEGER_TYPE) { tree temp = ar; ar = ind; ind = temp; } if (ar == error_mark_node) return ar; if (TREE_CODE (TREE_TYPE (ar)) != POINTER_TYPE) { error ("subscripted value is neither array nor pointer"); return error_mark_node; } if (TREE_CODE (TREE_TYPE (ind)) != INTEGER_TYPE) { error ("array subscript is not an integer"); return error_mark_node; } return build_indirect_ref (build_binary_op (PLUS_EXPR, ar, ind, 0), "array indexing"); }}/* 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. FUNCTION's data type may be a function type or a pointer-to-function. */treebuild_function_call (function, params) tree function, params;{ register tree fntype, fundecl = 0; register tree coerced_params; tree name = NULL_TREE, assembler_name = NULL_TREE; /* Strip NON_LVALUE_EXPRs, etc., since we aren't using as an lvalue. */ STRIP_TYPE_NOPS (function); /* Convert anything with function type to a pointer-to-function. */ if (TREE_CODE (function) == FUNCTION_DECL) { name = DECL_NAME (function); assembler_name = DECL_ASSEMBLER_NAME (function); /* Differs from default_conversion by not setting TREE_ADDRESSABLE (because calling an inline function does not mean the function needs to be separately compiled). */ fntype = build_type_variant (TREE_TYPE (function), TREE_READONLY (function), TREE_THIS_VOLATILE (function)); fundecl = function; function = build1 (ADDR_EXPR, build_pointer_type (fntype), function); } else function = default_conversion (function); fntype = TREE_TYPE (function); if (TREE_CODE (fntype) == ERROR_MARK) return error_mark_node; if (!(TREE_CODE (fntype) == POINTER_TYPE && TREE_CODE (TREE_TYPE (fntype)) == FUNCTION_TYPE)) { error ("called object is not a function"); return error_mark_node; } /* fntype now gets the type of function pointed to. */ fntype = TREE_TYPE (fntype); /* Convert the parameters to the types declared in the function prototype, or apply default promotions. */ coerced_params = convert_arguments (TYPE_ARG_TYPES (fntype), params, name, fundecl); /* Check for errors in format strings. */ if (warn_format && (name || assembler_name)) check_function_format (name, assembler_name, coerced_params); /* Recognize certain built-in functions so we can make tree-codes other than CALL_EXPR. We do this when it enables fold-const.c to do something useful. */ if (TREE_CODE (function) == ADDR_EXPR && TREE_CODE (TREE_OPERAND (function, 0)) == FUNCTION_DECL && DECL_BUILT_IN (TREE_OPERAND (function, 0))) switch (DECL_FUNCTION_CODE (TREE_OPERAND (function, 0))) { case BUILT_IN_ABS: case BUILT_IN_LABS: case BUILT_IN_FABS: if (coerced_params == 0) return integer_zero_node; return build_unary_op (ABS_EXPR, TREE_VALUE (coerced_params), 0); } { register tree result = build (CALL_EXPR, TREE_TYPE (fntype), function, coerced_params, NULL_TREE); TREE_SIDE_EFFECTS (result) = 1; if (TREE_TYPE (result) == void_type_node) return result; return require_complete_type (result); }}/* Convert the argument expressions in the list VALUES to the types in the list TYPELIST. The result is a list of converted argument expressions. If TYPELIST is exhausted, or when an element has NULL as its type, perform the default conversions. PARMLIST is the chain of parm decls for the function being called. It may be 0, if that info is not available. It is used only for generating error messages. NAME is an IDENTIFIER_NODE or 0. It is used only for error messages. This is also where warnings about wrong number of args are generated. Both VALUES and the returned value are chains of TREE_LIST nodes with the elements of the list in the TREE_VALUE slots of those nodes. */static treeconvert_arguments (typelist, values, name, fundecl) tree typelist, values, name, fundecl;{ register tree typetail, valtail; register tree result = NULL; int parmnum; /* Scan the given expressions and types, producing individual converted arguments and pushing them on RESULT in reverse order. */ for (valtail = values, typetail = typelist, parmnum = 0; valtail; valtail = TREE_CHAIN (valtail), parmnum++) { register tree type = typetail ? TREE_VALUE (typetail) : 0; register tree val = TREE_VALUE (valtail); if (type == void_type_node) { if (name) error ("too many arguments to function `%s'", IDENTIFIER_POINTER (name)); else error ("too many arguments to function"); break; } /* Strip NON_LVALUE_EXPRs since we aren't using as an lvalue. */ /* Do not use STRIP_NOPS here! We do not want an enumerator with value 0 to convert automatically to a pointer. */ if (TREE_CODE (val) == NON_LVALUE_EXPR) val = TREE_OPERAND (val, 0); if (TREE_CODE (TREE_TYPE (val)) == ARRAY_TYPE || TREE_CODE (TREE_TYPE (val)) == FUNCTION_TYPE) val = default_conversion (val); val = require_complete_type (val); if (type != 0) { /* Formal parm type is specified by a function prototype. */ tree parmval; if (TYPE_SIZE (type) == 0) { error ("type of formal parameter %d is incomplete", parmnum + 1); parmval = val; } else { /* Optionally warn about conversions that differ from the default conversions. */ if (warn_conversion) { int formal_prec = TYPE_PRECISION (type); if (INTEGRAL_TYPE_P (type) && TREE_CODE (TREE_TYPE (val)) == REAL_TYPE) warn_for_assignment ("%s as integer rather than floating due to prototype", (char *) 0, name, parmnum + 1); else if (TREE_CODE (type) == COMPLEX_TYPE && TREE_CODE (TREE_TYPE (val)) == REAL_TYPE)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -