📄 c-common.c
字号:
/* Subroutines shared by all languages that are variants of C. Copyright (C) 1992, 1993, 1994, 1995 Free Software Foundation, Inc.This file is part of GNU CC.GNU CC is free software; you can redistribute it and/or modifyit under the terms of the GNU General Public License as published bythe 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 ofMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See theGNU General Public License for more details.You should have received a copy of the GNU General Public Licensealong with GNU CC; see the file COPYING. If not, write tothe Free Software Foundation, 59 Temple Place - Suite 330,Boston, MA 02111-1307, 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;enum attrs {A_PACKED, A_NOCOMMON, A_NORETURN, A_CONST, A_T_UNION, A_CONSTRUCTOR, A_DESTRUCTOR, A_MODE, A_SECTION, A_ALIGNED, A_UNUSED, A_FORMAT, A_WEAK, A_ALIAS};static void declare_hidden_char_array PROTO((char *, char *));static void add_attribute PROTO((enum attrs, char *, int, int, int));static void init_attributes PROTO((void));/* Make bindings for __FUNCTION__ and __PRETTY_FUNCTION__. */voiddeclare_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 voiddeclare_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_ARTIFICIAL (decl) = 1; 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. */treecombine_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; } /* Compute the number of elements, for the array type. */ 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;}/* To speed up processing of attributes, we maintain an array of IDENTIFIER_NODES and the corresponding attribute types. *//* Array to hold attribute information. */static struct {enum attrs id; tree name; int min, max, decl_req;} attrtab[50];static int attrtab_idx = 0;/* Add an entry to the attribute table above. */static voidadd_attribute (id, string, min_len, max_len, decl_req) enum attrs id; char *string; int min_len, max_len; int decl_req;{ char buf[100]; attrtab[attrtab_idx].id = id; attrtab[attrtab_idx].name = get_identifier (string); attrtab[attrtab_idx].min = min_len; attrtab[attrtab_idx].max = max_len; attrtab[attrtab_idx++].decl_req = decl_req; sprintf (buf, "__%s__", string); attrtab[attrtab_idx].id = id; attrtab[attrtab_idx].name = get_identifier (buf); attrtab[attrtab_idx].min = min_len; attrtab[attrtab_idx].max = max_len; attrtab[attrtab_idx++].decl_req = decl_req;}/* Initialize attribute table. */static voidinit_attributes (){ add_attribute (A_PACKED, "packed", 0, 0, 0); add_attribute (A_NOCOMMON, "nocommon", 0, 0, 1); add_attribute (A_NORETURN, "noreturn", 0, 0, 1); add_attribute (A_NORETURN, "volatile", 0, 0, 1); add_attribute (A_UNUSED, "unused", 0, 0, 1); add_attribute (A_CONST, "const", 0, 0, 1); add_attribute (A_T_UNION, "transparent_union", 0, 0, 0); add_attribute (A_CONSTRUCTOR, "constructor", 0, 0, 1); add_attribute (A_DESTRUCTOR, "destructor", 0, 0, 1); add_attribute (A_MODE, "mode", 1, 1, 1); add_attribute (A_SECTION, "section", 1, 1, 1); add_attribute (A_ALIGNED, "aligned", 0, 1, 0); add_attribute (A_FORMAT, "format", 3, 3, 1); add_attribute (A_WEAK, "weak", 0, 0, 1); add_attribute (A_ALIAS, "alias", 1, 1, 1);}/* Process the attributes listed in ATTRIBUTES and PREFIX_ATTRIBUTES and install them in NODE, which is either a DECL (including a TYPE_DECL) or a TYPE. PREFIX_ATTRIBUTES can appear after the declaration specifiers and declaration modifiers but before the declaration proper. */voiddecl_attributes (node, attributes, prefix_attributes) tree node, attributes, prefix_attributes;{ tree decl = 0, type; int is_type; tree a; if (attrtab_idx == 0) init_attributes (); if (TREE_CODE_CLASS (TREE_CODE (node)) == 'd') { decl = node; type = TREE_TYPE (decl); is_type = TREE_CODE (node) == TYPE_DECL; } else if (TREE_CODE_CLASS (TREE_CODE (node)) == 't') type = node, is_type = 1; attributes = chainon (prefix_attributes, attributes); for (a = attributes; a; a = TREE_CHAIN (a)) { tree name = TREE_PURPOSE (a); tree args = TREE_VALUE (a); int i; enum attrs id; for (i = 0; i < attrtab_idx; i++) if (attrtab[i].name == name) break; if (i == attrtab_idx) { if (! valid_machine_attribute (name, args, decl, type)) warning ("`%s' attribute directive ignored", IDENTIFIER_POINTER (name)); continue; } else if (attrtab[i].decl_req && decl == 0) { warning ("`%s' attribute does not apply to types", IDENTIFIER_POINTER (name)); continue; } else if (list_length (args) < attrtab[i].min || list_length (args) > attrtab[i].max) { error ("wrong number of arguments specified for `%s' attribute", IDENTIFIER_POINTER (name)); continue; } id = attrtab[i].id; switch (id) { case A_PACKED: if (is_type) TYPE_PACKED (type) = 1; else 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 ("`%s' attribute ignored", IDENTIFIER_POINTER (name)); break; case A_NOCOMMON: if (TREE_CODE (decl) == VAR_DECL) DECL_COMMON (decl) = 0; else warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name)); break; case A_NORETURN: 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) TREE_TYPE (decl) = type = build_pointer_type (build_type_variant (TREE_TYPE (type), TREE_READONLY (TREE_TYPE (type)), 1)); else warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name)); break; case A_UNUSED: if (TREE_CODE (decl) == PARM_DECL || TREE_CODE (decl) == VAR_DECL || TREE_CODE (decl) == FUNCTION_DECL) TREE_USED (decl) = 1; else warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name)); break; case A_CONST: 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 ( "`%s' attribute ignored", IDENTIFIER_POINTER (name)); break; case A_T_UNION: if (is_type && TREE_CODE (type) == UNION_TYPE && (decl == 0 || TYPE_MODE (type) == DECL_MODE (TYPE_FIELDS (type)))) TYPE_TRANSPARENT_UNION (type) = 1; else if (decl != 0 && TREE_CODE (decl) == PARM_DECL && TREE_CODE (type) == UNION_TYPE && TYPE_MODE (type) == DECL_MODE (TYPE_FIELDS (type))) DECL_TRANSPARENT_UNION (decl) = 1; else warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name)); break; case A_CONSTRUCTOR: if (TREE_CODE (decl) == FUNCTION_DECL && TREE_CODE (type) == FUNCTION_TYPE && decl_function_context (decl) == 0) { DECL_STATIC_CONSTRUCTOR (decl) = 1; TREE_USED (decl) = 1; } else warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name)); break; case A_DESTRUCTOR: if (TREE_CODE (decl) == FUNCTION_DECL && TREE_CODE (type) == FUNCTION_TYPE && decl_function_context (decl) == 0) { DECL_STATIC_DESTRUCTOR (decl) = 1; TREE_USED (decl) = 1; } else warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name)); break; case A_MODE: if (TREE_CODE (TREE_VALUE (args)) != IDENTIFIER_NODE) warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name)); else { int j; char *p = IDENTIFIER_POINTER (TREE_VALUE (args)); int len = strlen (p); enum machine_mode mode = VOIDmode; tree typefm;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -