#define YYDEBUG 1
#include "config.h"
#include "system.h"
#include "input.h"
#include "tree.h"
#include "cp-tree.h"
#include "cpplib.h"
#include "c-lex.h"
#include "lex.h"
#include "cp-parse.h"
#include "flags.h"
#include "c-pragma.h"
#include "toplev.h"
#include "output.h"
#include "ggc.h"
#include "tm_p.h"
#include "timevar.h"
#include "diagnostic.h"
#ifdef MULTIBYTE_CHARS
#include "mbchar.h"
#include <locale.h>
#endif
#ifdef PFE
#include "pfe/pfe.h"
#endif
#include "genindex.h"
extern void yyprint PARAMS ((FILE *, int, YYSTYPE));
static int interface_strcmp PARAMS ((const char *));
static int *init_cpp_parse PARAMS ((void));
static void init_cp_pragma PARAMS ((void));
static tree parse_strconst_pragma PARAMS ((const char *, int));
static void handle_pragma_vtable PARAMS ((cpp_reader *));
static void handle_pragma_unit PARAMS ((cpp_reader *));
static void handle_pragma_interface PARAMS ((cpp_reader *));
static void handle_pragma_implementation PARAMS ((cpp_reader *));
static void handle_pragma_java_exceptions PARAMS ((cpp_reader *));
#ifdef GATHER_STATISTICS
#ifdef REDUCE_LENGTH
static int reduce_cmp PARAMS ((int *, int *));
static int token_cmp PARAMS ((int *, int *));
#endif
#endif
static int is_global PARAMS ((tree));
static void init_operators PARAMS ((void));
static void copy_lang_type PARAMS ((tree));
#ifdef __STDC__
#define CONSTRAINT(name, expr) extern int constraint_##name [(expr) ? 1 : -1]
#else
#define CONSTRAINT(name, expr) extern int constraint_name [(expr) ? 1 : -1]
#endif
#include "cpplib.h"
extern int yychar;
extern YYSTYPE yylval;
int warn_traditional = 0;
int flag_digraphs = 1;
tree lastiddecl;
extern int *token_count;
struct impl_files
{
const char *filename;
struct impl_files *next;
};
static struct impl_files *impl_file_chain;
tree
make_pointer_declarator (cv_qualifiers, target)
tree cv_qualifiers, target;
{
if (target && TREE_CODE (target) == IDENTIFIER_NODE
&& ANON_AGGRNAME_P (target))
error ("type name expected before `*'");
target = build_nt (INDIRECT_REF, target);
TREE_TYPE (target) = cv_qualifiers;
return target;
}
tree
make_reference_declarator (cv_qualifiers, target)
tree cv_qualifiers, target;
{
if (target)
{
if (TREE_CODE (target) == ADDR_EXPR)
{
error ("cannot declare references to references");
return target;
}
if (TREE_CODE (target) == INDIRECT_REF)
{
error ("cannot declare pointers to references");
return target;
}
if (TREE_CODE (target) == IDENTIFIER_NODE && ANON_AGGRNAME_P (target))
error ("type name expected before `&'");
}
target = build_nt (ADDR_EXPR, target);
TREE_TYPE (target) = cv_qualifiers;
return target;
}
tree
make_call_declarator (target, parms, cv_qualifiers, exception_specification)
tree target, parms, cv_qualifiers, exception_specification;
{
target = build_nt (CALL_EXPR, target,
tree_cons (parms, cv_qualifiers, NULL_TREE),
NULL_TREE);
CALL_DECLARATOR_EXCEPTION_SPEC (target) = exception_specification;
return target;
}
void
set_quals_and_spec (call_declarator, cv_qualifiers, exception_specification)
tree call_declarator, cv_qualifiers, exception_specification;
{
CALL_DECLARATOR_QUALS (call_declarator) = cv_qualifiers;
CALL_DECLARATOR_EXCEPTION_SPEC (call_declarator) = exception_specification;
}
int interface_only;
int interface_unknown;
#define DEFTREECODE(SYM, NAME, TYPE, LENGTH) TYPE,
static const char cplus_tree_code_type[] = {
'x',
#include "cp-tree.def"
};
#undef DEFTREECODE
#define DEFTREECODE(SYM, NAME, TYPE, LENGTH) LENGTH,
static const int cplus_tree_code_length[] = {
0,
#include "cp-tree.def"
};
#undef DEFTREECODE
#define DEFTREECODE(SYM, NAME, TYPE, LEN) NAME,
static const char *const cplus_tree_code_name[] = {
"@@dummy",
#include "cp-tree.def"
};
#undef DEFTREECODE
void
cxx_post_options ()
{
c_common_post_options ();
}
void
cxx_init_options (lang)
enum c_language_kind lang;
{
c_common_init_options (lang);
flag_exceptions = 1;
diagnostic_line_cutoff (global_dc) = 80;
diagnostic_prefixing_rule (global_dc) = DIAGNOSTICS_SHOW_PREFIX_ONCE;
if (compiling_objc)
set_index_lang (PB_INDEX_LANG_OBJCP);
else
set_index_lang (PB_INDEX_LANG_CP);
}
void
cxx_finish ()
{
c_common_finish ();
}
static int *
init_cpp_parse ()
{
#ifdef GATHER_STATISTICS
#ifdef REDUCE_LENGTH
reduce_count = (int *) xcalloc (sizeof (int), (REDUCE_LENGTH + 1));
reduce_count += 1;
token_count = (int *) xcalloc (sizeof (int), (TOKEN_LENGTH + 1));
token_count += 1;
#endif
#endif
return token_count;
}
operator_name_info_t operator_name_info[(int) LAST_CPLUS_TREE_CODE];
operator_name_info_t assignment_operator_name_info[(int) LAST_CPLUS_TREE_CODE];
#define DEF_OPERATOR(NAME, C, M, AR, AP) \
CONSTRAINT (C, sizeof "operator " + sizeof NAME <= 256);
#include "operators.def"
#undef DEF_OPERATOR
static void
init_operators ()
{
tree identifier;
char buffer[256];
struct operator_name_info_t *oni;
#define DEF_OPERATOR(NAME, CODE, MANGLING, ARITY, ASSN_P) \
sprintf (buffer, ISALPHA (NAME[0]) ? "operator %s" : "operator%s", NAME); \
identifier = get_identifier (buffer); \
IDENTIFIER_OPNAME_P (identifier) = 1; \
\
oni = (ASSN_P \
? &assignment_operator_name_info[(int) CODE] \
: &operator_name_info[(int) CODE]); \
oni->identifier = identifier; \
oni->name = PFE_SAVESTRING (NAME); \
oni->mangled_name = PFE_SAVESTRING (MANGLING);
#include "operators.def"
#undef DEF_OPERATOR
operator_name_info[(int) ERROR_MARK].identifier
= get_identifier ("<invalid operator>");
operator_name_info [(int) INIT_EXPR].name
= operator_name_info [(int) MODIFY_EXPR].name;
operator_name_info [(int) EXACT_DIV_EXPR].name = PFE_SAVESTRING ("(ceiling /)");
operator_name_info [(int) CEIL_DIV_EXPR].name = PFE_SAVESTRING ("(ceiling /)");
operator_name_info [(int) FLOOR_DIV_EXPR].name = PFE_SAVESTRING ("(floor /)");
operator_name_info [(int) ROUND_DIV_EXPR].name = PFE_SAVESTRING ("(round /)");
operator_name_info [(int) CEIL_MOD_EXPR].name = PFE_SAVESTRING ("(ceiling %)");
operator_name_info [(int) FLOOR_MOD_EXPR].name = PFE_SAVESTRING ("(floor %)");
operator_name_info [(int) ROUND_MOD_EXPR].name = PFE_SAVESTRING ("(round %)");
operator_name_info [(int) ABS_EXPR].name = PFE_SAVESTRING ("abs");
operator_name_info [(int) FFS_EXPR].name = PFE_SAVESTRING ("ffs");
operator_name_info [(int) BIT_ANDTC_EXPR].name = PFE_SAVESTRING ("&~");
operator_name_info [(int) TRUTH_AND_EXPR].name = PFE_SAVESTRING ("strict &&");
operator_name_info [(int) TRUTH_OR_EXPR].name = PFE_SAVESTRING ("strict ||");
operator_name_info [(int) IN_EXPR].name = PFE_SAVESTRING ("in");
operator_name_info [(int) RANGE_EXPR].name = PFE_SAVESTRING ("...");
operator_name_info [(int) CONVERT_EXPR].name = PFE_SAVESTRING ("+");
assignment_operator_name_info [(int) EXACT_DIV_EXPR].name
= PFE_SAVESTRING ("(exact /=)");
assignment_operator_name_info [(int) CEIL_DIV_EXPR].name
= PFE_SAVESTRING ("(ceiling /=)");
assignment_operator_name_info [(int) FLOOR_DIV_EXPR].name
= PFE_SAVESTRING ("(floor /=)");
assignment_operator_name_info [(int) ROUND_DIV_EXPR].name
= PFE_SAVESTRING ("(round /=)");
assignment_operator_name_info [(int) CEIL_MOD_EXPR].name
= PFE_SAVESTRING ("(ceiling %=)");
assignment_operator_name_info [(int) FLOOR_MOD_EXPR].name
= PFE_SAVESTRING ("(floor %=)");
assignment_operator_name_info [(int) ROUND_MOD_EXPR].name
= PFE_SAVESTRING ("(round %=)");
}
struct resword
{
const char *const word;
const ENUM_BITFIELD(rid) rid : 16;
const unsigned int disable : 16;
};
#define D_EXT 0x01
#define D_ASM 0x02
#define D_OPNAME 0x04
#define D_OBJC 0x10
#define D_ALTIVEC 0x80
CONSTRAINT(ridbits_fit, RID_LAST_MODIFIER < sizeof(unsigned long) * CHAR_BIT);
static const struct resword reswords[] =
{
{ "_Complex", RID_COMPLEX, 0 },
{ "__FUNCTION__", RID_FUNCTION_NAME, 0 },
{ "__PRETTY_FUNCTION__", RID_PRETTY_FUNCTION_NAME, 0 },
{ "__alignof", RID_ALIGNOF, 0 },
{ "__alignof__", RID_ALIGNOF, 0 },
{ "__asm", RID_ASM, 0 },
{ "__asm__", RID_ASM, 0 },
{ "__attribute", RID_ATTRIBUTE, 0 },
{ "__attribute__", RID_ATTRIBUTE, 0 },
{ "__builtin_va_arg", RID_VA_ARG, 0 },
{ "__complex", RID_COMPLEX, 0 },
{ "__complex__", RID_COMPLEX, 0 },
{ "__const", RID_CONST, 0 },
{ "__const__", RID_CONST, 0 },
{ "__extension__", RID_EXTENSION, 0 },
{ "__func__", RID_C99_FUNCTION_NAME, 0 },
{ "__imag", RID_IMAGPART, 0 },
{ "__imag__", RID_IMAGPART, 0 },
{ "__inline", RID_INLINE, 0 },
{ "__inline__", RID_INLINE, 0 },
{ "__label__", RID_LABEL, 0 },
{ "__null", RID_NULL, 0 },
{ "__private_extern__", RID_PRIVATE_EXTERN, 0 },
{ "__real", RID_REALPART, 0 },
{ "__real__", RID_REALPART, 0 },
{ "__restrict", RID_RESTRICT, 0 },
{ "__restrict__", RID_RESTRICT, 0 },
{ "__signed", RID_SIGNED, 0 },
{ "__signed__", RID_SIGNED, 0 },
{ "__typeof", RID_TYPEOF, 0 },
{ "__typeof__", RID_TYPEOF, 0 },
{ "__volatile", RID_VOLATILE, 0 },
{ "__volatile__", RID_VOLATILE, 0 },
{ "asm", RID_ASM, D_ASM },
{ "and", RID_AND, D_OPNAME },
{ "and_eq", RID_AND_EQ, D_OPNAME },
{ "auto", RID_AUTO, 0 },
{ "bitand", RID_BITAND, D_OPNAME },
{ "bitor", RID_BITOR, D_OPNAME },
{ "bool", RID_BOOL, 0 },
{ "break", RID_BREAK, 0 },
{ "case", RID_CASE, 0 },
{ "catch", RID_CATCH, 0 },
{ "char", RID_CHAR, 0 },
{ "class", RID_CLASS, 0 },
{ "compl", RID_COMPL, D_OPNAME },
{ "const", RID_CONST, 0 },
{ "const_cast", RID_CONSTCAST, 0 },
{ "continue", RID_CONTINUE, 0 },
{ "default", RID_DEFAULT, 0 },
{ "delete", RID_DELETE, 0 },
{ "do", RID_DO, 0 },
{ "double", RID_DOUBLE, 0 },
{ "dynamic_cast", RID_DYNCAST, 0 },
{ "else", RID_ELSE, 0 },
{ "enum", RID_ENUM, 0 },
{ "explicit", RID_EXPLICIT, 0 },
{ "export", RID_EXPORT, 0 },
{ "extern", RID_EXTERN, 0 },
{ "false", RID_FALSE, 0 },
{ "float", RID_FLOAT, 0 },
{ "for", RID_FOR, 0 },
{ "friend", RID_FRIEND, 0 },
{ "goto", RID_GOTO, 0 },
{ "if", RID_IF, 0 },
{ "inline", RID_INLINE, 0 },
{ "int", RID_INT, 0 },
{ "long", RID_LONG, 0 },
{ "mutable", RID_MUTABLE, 0 },
{ "namespace", RID_NAMESPACE, 0 },
{ "new", RID_NEW, 0 },
{ "not", RID_NOT, D_OPNAME },
{ "not_eq", RID_NOT_EQ, D_OPNAME },
{ "operator", RID_OPERATOR, 0 },
{ "or", RID_OR, D_OPNAME },
{ "or_eq", RID_OR_EQ, D_OPNAME },
{ "private", RID_PRIVATE, 0 },
{ "protected", RID_PROTECTED, 0 },
{ "public", RID_PUBLIC, 0 },
{ "register", RID_REGISTER, 0 },
{ "reinterpret_cast", RID_REINTCAST, 0 },
{ "return", RID_RETURN, 0 },
{ "short", RID_SHORT, 0 },
{ "signed", RID_SIGNED, 0 },
{ "sizeof", RID_SIZEOF, 0 },
{ "static", RID_STATIC, 0 },
{ "static_cast", RID_STATCAST, 0 },
{ "struct", RID_STRUCT, 0 },
{ "switch", RID_SWITCH, 0 },
{ "template", RID_TEMPLATE, 0 },
{ "this", RID_THIS, 0 },
{ "throw", RID_THROW, 0 },
{ "true", RID_TRUE, 0 },
{ "try", RID_TRY, 0 },
{ "typedef", RID_TYPEDEF, 0 },
{ "typename", RID_TYPENAME, 0 },
{ "typeid", RID_TYPEID, 0 },
{ "typeof", RID_TYPEOF, D_ASM|D_EXT },
{ "union", RID_UNION, 0 },
{ "unsigned", RID_UNSIGNED, 0 },
{ "using", RID_USING, 0 },
{ "virtual", RID_VIRTUAL, 0 },
{ "void", RID_VOID, 0 },
{ "volatile", RID_VOLATILE, 0 },
{ "wchar_t", RID_WCHAR, 0 },
{ "while", RID_WHILE, 0 },
{ "xor", RID_XOR, D_OPNAME },
{ "xor_eq", RID_XOR_EQ, D_OPNAME },
{ "id", RID_ID, D_OBJC },
{ "compatibility_alias", RID_AT_ALIAS, D_OBJC },
{ "defs", RID_AT_DEFS, D_OBJC },
{ "encode", RID_AT_ENCODE, D_OBJC },
{ "end", RID_AT_END, D_OBJC },
{ "implementation", RID_AT_IMPLEMENTATION, D_OBJC },
{ "interface", RID_AT_INTERFACE, D_OBJC },
{ "protocol", RID_AT_PROTOCOL, D_OBJC },
{ "selector", RID_AT_SELECTOR, D_OBJC },
{ "bycopy", RID_BYCOPY, D_OBJC },
{ "byref", RID_BYREF, D_OBJC },
{ "in", RID_IN, D_OBJC },
{ "inout", RID_INOUT, D_OBJC },
{ "oneway", RID_ONEWAY, D_OBJC },
{ "out", RID_OUT, D_OBJC },
{ "vec_step", RID_ALTIVEC_VEC_STEP, D_ALTIVEC },
{ "__vector", RID_ALTIVEC_VECTOR, D_ALTIVEC },
{ "__pixel", RID_ALTIVEC_PIXEL, D_ALTIVEC },
{ "__bool", RID_ALTIVEC_BOOL, D_ALTIVEC },
{ "vector", RID_ALTIVEC_VECTOR, D_ALTIVEC },
{ "pixel", RID_ALTIVEC_PIXEL, D_ALTIVEC },
};
#define N_reswords (sizeof reswords / sizeof (struct resword))
const short rid_to_yy[RID_MAX] =
{
SCSPEC,
TYPESPEC,
TYPESPEC,
CV_QUALIFIER,
SCSPEC,
SCSPEC,
SCSPEC,
TYPESPEC,
SCSPEC,
CV_QUALIFIER,
TYPESPEC,
SCSPEC,
CV_QUALIFIER,
0,
0,
TYPESPEC,
SCSPEC,
SCSPEC,
SCSPEC,
SCSPEC,
EXPORT,
SCSPEC,
CV_QUALIFIER,
CV_QUALIFIER,
CV_QUALIFIER,
CV_QUALIFIER,
CV_QUALIFIER,
CV_QUALIFIER,
TYPESPEC,
TYPESPEC,
TYPESPEC,
TYPESPEC,
TYPESPEC,
TYPESPEC,
TYPESPEC,
TYPESPEC,
ENUM,
AGGR,
AGGR,
IF,
ELSE,
WHILE,
DO,
FOR,
SWITCH,
CASE,
DEFAULT,
BREAK,
CONTINUE,
RETURN_KEYWORD,
GOTO,
SIZEOF,
VEC_STEP,
ASM_KEYWORD,
TYPEOF,
ALIGNOF,
ATTRIBUTE,
VA_ARG,
EXTENSION,
IMAGPART,
REALPART,
LABEL,
0,
0,
0,
0,
0,
VAR_FUNC_NAME,
VAR_FUNC_NAME,
VAR_FUNC_NAME,
TYPESPEC,
TYPESPEC,
AGGR,
VISSPEC,
VISSPEC,
VISSPEC,
TEMPLATE,
CONSTANT,
CATCH,
DELETE,
CXX_FALSE,
NAMESPACE,
NEW,
OPERATOR,
THIS,
THROW,
CXX_TRUE,
TRY,
TYPENAME_KEYWORD,
TYPEID,
USING,
CONST_CAST,
DYNAMIC_CAST,
REINTERPRET_CAST,
STATIC_CAST,
ANDAND,
ASSIGN,
'!',
EQCOMPARE,
OROR,
ASSIGN,
'^',
ASSIGN,
'&',
'|',
'~',
OBJECTNAME,
ENCODE,
END,
CLASS,
ALIAS,
DEFS,
PRIVATE,
PROTECTED,
PUBLIC,
PROTOCOL,
SELECTOR,
INTERFACE,
IMPLEMENTATION
};
void
init_reswords ()
{
unsigned int i;
tree id;
int mask = ((flag_operator_names ? 0 : D_OPNAME)
| (flag_no_asm ? D_ASM : 0)
| (flag_no_gnu_keywords ? D_EXT : 0));
if (!compiling_objc)
mask |= D_OBJC;
if (!flag_altivec)
mask |= D_ALTIVEC;
ridpointers = (tree *) xcalloc ((int) RID_MAX, sizeof (tree));
for (i = 0; i < N_reswords; i++)
{
id = get_identifier (reswords[i].word);
C_RID_CODE (id) = reswords[i].rid;
ridpointers [(int) reswords[i].rid] = id;
if (! (reswords[i].disable & mask))
C_IS_RESERVED_WORD (id) = 1;
}
if (flag_preprocessed)
{
id = get_identifier ("__private_extern__");
C_RID_CODE (id) = RID_EXTERN;
}
}
static void
init_cp_pragma ()
{
cpp_register_pragma (parse_in, 0, "vtable", handle_pragma_vtable);
cpp_register_pragma (parse_in, 0, "unit", handle_pragma_unit);
cpp_register_pragma (parse_in, 0, "interface", handle_pragma_interface);
cpp_register_pragma (parse_in, 0, "implementation",
handle_pragma_implementation);
cpp_register_pragma (parse_in, "GCC", "interface", handle_pragma_interface);
cpp_register_pragma (parse_in, "GCC", "implementation",
handle_pragma_implementation);
cpp_register_pragma (parse_in, "GCC", "java_exceptions",
handle_pragma_java_exceptions);
}
void
add_cpp_tree_codes ()
{
memcpy (tree_code_type + (int) LAST_C_TREE_CODE,
cplus_tree_code_type,
(int)LAST_CPLUS_TREE_CODE - (int)LAST_C_TREE_CODE);
memcpy (tree_code_length + (int) LAST_C_TREE_CODE,
cplus_tree_code_length,
(LAST_CPLUS_TREE_CODE - (int)LAST_C_TREE_CODE) * sizeof (int));
memcpy (tree_code_name + (int) LAST_C_TREE_CODE,
cplus_tree_code_name,
(LAST_CPLUS_TREE_CODE - (int)LAST_C_TREE_CODE) * sizeof (char *));
}
const char *
cxx_init (filename)
const char *filename;
{
decl_printable_name = lang_printable_name;
input_filename = PFE_SAVESTRING ("<internal>");
init_reswords ();
init_spew ();
init_tree ();
init_cplus_expand ();
init_cp_semantics ();
add_c_tree_codes ();
add_cpp_tree_codes ();
init_operators ();
init_method ();
init_error ();
current_function_decl = NULL;
class_type_node = build_int_2 (class_type, 0);
TREE_TYPE (class_type_node) = class_type_node;
ridpointers[(int) RID_CLASS] = class_type_node;
record_type_node = build_int_2 (record_type, 0);
TREE_TYPE (record_type_node) = record_type_node;
ridpointers[(int) RID_STRUCT] = record_type_node;
union_type_node = build_int_2 (union_type, 0);
TREE_TYPE (union_type_node) = union_type_node;
ridpointers[(int) RID_UNION] = union_type_node;
enum_type_node = build_int_2 (enum_type, 0);
TREE_TYPE (enum_type_node) = enum_type_node;
ridpointers[(int) RID_ENUM] = enum_type_node;
#ifdef PFE
if (pfe_operation == PFE_LOAD)
{
pfe_cxx_init_decl_processing ();
}
else
cxx_init_decl_processing ();
#else
cxx_init_decl_processing ();
#endif
null_node = build_int_2 (0, 0);
TREE_TYPE (null_node) = type_for_size (POINTER_SIZE, 0);
ridpointers[RID_NULL] = null_node;
token_count = init_cpp_parse ();
interface_unknown = 1;
filename = c_common_init (filename);
init_cp_pragma ();
init_repo (filename);
return filename;
}
inline void
yyprint (file, yychar, yylval)
FILE *file;
int yychar;
YYSTYPE yylval;
{
tree t;
switch (yychar)
{
case IDENTIFIER:
case TYPENAME:
case TYPESPEC:
case PTYPENAME:
case PFUNCNAME:
case IDENTIFIER_DEFN:
case TYPENAME_DEFN:
case PTYPENAME_DEFN:
case SCSPEC:
case PRE_PARSED_CLASS_DECL:
t = yylval.ttype;
if (TREE_CODE (t) == TYPE_DECL || TREE_CODE (t) == TEMPLATE_DECL)
{
fprintf (file, " `%s'", IDENTIFIER_POINTER (DECL_NAME (t)));
break;
}
my_friendly_assert (TREE_CODE (t) == IDENTIFIER_NODE, 224);
if (IDENTIFIER_POINTER (t))
fprintf (file, " `%s'", IDENTIFIER_POINTER (t));
break;
case AGGR:
if (yylval.ttype == class_type_node)
fprintf (file, " `class'");
else if (yylval.ttype == record_type_node)
fprintf (file, " `struct'");
else if (yylval.ttype == union_type_node)
fprintf (file, " `union'");
else if (yylval.ttype == enum_type_node)
fprintf (file, " `enum'");
else
abort ();
break;
case CONSTANT:
t = yylval.ttype;
if (TREE_CODE (t) == INTEGER_CST)
fprintf (file,
#if HOST_BITS_PER_WIDE_INT == 64
#if HOST_BITS_PER_WIDE_INT == HOST_BITS_PER_INT
" 0x%x%016x",
#else
#if HOST_BITS_PER_WIDE_INT == HOST_BITS_PER_LONG
" 0x%lx%016lx",
#else
" 0x%llx%016llx",
#endif
#endif
#else
#if HOST_BITS_PER_WIDE_INT != HOST_BITS_PER_INT
" 0x%lx%08lx",
#else
" 0x%x%08x",
#endif
#endif
TREE_INT_CST_HIGH (t), TREE_INT_CST_LOW (t));
break;
}
}
#if defined(GATHER_STATISTICS) && defined(REDUCE_LENGTH)
static int *reduce_count;
#endif
int *token_count;
#if 0
#define REDUCE_LENGTH (sizeof (yyr2) / sizeof (yyr2[0]))
#define TOKEN_LENGTH (256 + sizeof (yytname) / sizeof (yytname[0]))
#endif
#ifdef GATHER_STATISTICS
#ifdef REDUCE_LENGTH
void
yyhook (yyn)
int yyn;
{
reduce_count[yyn] += 1;
}
static int
reduce_cmp (p, q)
int *p, *q;
{
return reduce_count[*q] - reduce_count[*p];
}
static int
token_cmp (p, q)
int *p, *q;
{
return token_count[*q] - token_count[*p];
}
#endif
#endif
void
print_parse_statistics ()
{
#ifdef GATHER_STATISTICS
#ifdef REDUCE_LENGTH
#if YYDEBUG != 0
int i;
int maxlen = REDUCE_LENGTH;
unsigned *sorted;
if (reduce_count[-1] == 0)
return;
if (TOKEN_LENGTH > REDUCE_LENGTH)
maxlen = TOKEN_LENGTH;
sorted = (unsigned *) alloca (sizeof (int) * maxlen);
for (i = 0; i < TOKEN_LENGTH; i++)
sorted[i] = i;
qsort (sorted, TOKEN_LENGTH, sizeof (int), token_cmp);
for (i = 0; i < TOKEN_LENGTH; i++)
{
int idx = sorted[i];
if (token_count[idx] == 0)
break;
if (token_count[idx] < token_count[-1])
break;
fprintf (stderr, "token %d, `%s', count = %d\n",
idx, yytname[YYTRANSLATE (idx)], token_count[idx]);
}
fprintf (stderr, "\n");
for (i = 0; i < REDUCE_LENGTH; i++)
sorted[i] = i;
qsort (sorted, REDUCE_LENGTH, sizeof (int), reduce_cmp);
for (i = 0; i < REDUCE_LENGTH; i++)
{
int idx = sorted[i];
if (reduce_count[idx] == 0)
break;
if (reduce_count[idx] < reduce_count[-1])
break;
fprintf (stderr, "rule %d, line %d, count = %d\n",
idx, yyrline[idx], reduce_count[idx]);
}
fprintf (stderr, "\n");
#endif
#endif
#endif
}
void
cxx_set_yydebug (value)
int value;
{
#if YYDEBUG != 0
extern int yydebug;
yydebug = value;
#else
warning ("YYDEBUG not defined");
#endif
}
void
extract_interface_info ()
{
struct c_fileinfo *finfo = 0;
if (flag_alt_external_templates)
{
tree til = tinst_for_decl ();
if (til)
finfo = get_fileinfo (TINST_FILE (til));
}
if (!finfo)
finfo = get_fileinfo (input_filename);
interface_only = finfo->interface_only;
interface_unknown = finfo->interface_unknown;
}
static int
interface_strcmp (s)
const char *s;
{
struct impl_files *ifiles;
const char *s1;
for (ifiles = impl_file_chain; ifiles; ifiles = ifiles->next)
{
const char *t1 = ifiles->filename;
s1 = s;
if (*s1 != *t1 || *s1 == 0)
continue;
while (*s1 == *t1 && *s1 != 0)
s1++, t1++;
if (*s1 == *t1)
return 0;
if (strchr (s1, '.') || strchr (t1, '.'))
continue;
if (*s1 == '\0' || s1[-1] != '.' || t1[-1] != '.')
continue;
return 0;
}
return 1;
}
void
check_for_missing_semicolon (type)
tree type;
{
if (yychar < 0)
yychar = yylex ();
if ((yychar > 255
&& yychar != SCSPEC
&& yychar != IDENTIFIER
&& yychar != TYPENAME
&& yychar != CV_QUALIFIER
&& yychar != SELFNAME)
|| yychar == 0 )
{
if (TYPE_ANONYMOUS_P (type))
error ("semicolon missing after %s declaration",
TREE_CODE (type) == ENUMERAL_TYPE ? "enum" : "struct");
else
error ("semicolon missing after declaration of `%T'", type);
shadow_tag (build_tree_list (0, type));
}
clear_anon_tags ();
}
void
note_got_semicolon (type)
tree type;
{
if (!TYPE_P (type))
abort ();
if (CLASS_TYPE_P (type))
CLASSTYPE_GOT_SEMICOLON (type) = 1;
}
void
note_list_got_semicolon (declspecs)
tree declspecs;
{
tree link;
for (link = declspecs; link; link = TREE_CHAIN (link))
{
tree type = TREE_VALUE (link);
if (type && TYPE_P (type))
note_got_semicolon (type);
}
clear_anon_tags ();
}
static tree
parse_strconst_pragma (name, opt)
const char *name;
int opt;
{
tree result, x;
enum cpp_ttype t;
t = c_lex (&x);
if (t == CPP_STRING)
{
result = x;
if (c_lex (&x) != CPP_EOF)
warning ("junk at end of #pragma %s", name);
return result;
}
if (t == CPP_EOF && opt)
return 0;
error ("invalid #pragma %s", name);
return (tree)-1;
}
static void
handle_pragma_vtable (dfile)
cpp_reader *dfile ATTRIBUTE_UNUSED;
{
parse_strconst_pragma ("vtable", 0);
sorry ("#pragma vtable no longer supported");
}
static void
handle_pragma_unit (dfile)
cpp_reader *dfile ATTRIBUTE_UNUSED;
{
parse_strconst_pragma ("unit", 0);
}
static void
handle_pragma_interface (dfile)
cpp_reader *dfile ATTRIBUTE_UNUSED;
{
tree fname = parse_strconst_pragma ("interface", 1);
struct c_fileinfo *finfo;
const char *main_filename;
if (fname == (tree)-1)
return;
else if (fname == 0)
main_filename = lbasename (input_filename);
else
main_filename = TREE_STRING_POINTER (fname);
finfo = get_fileinfo (input_filename);
if (impl_file_chain == 0)
{
if (main_input_filename == 0)
main_input_filename = input_filename;
}
interface_only = interface_strcmp (main_filename);
#ifdef MULTIPLE_SYMBOL_SPACES
if (! interface_only)
#endif
interface_unknown = 0;
finfo->interface_only = interface_only;
finfo->interface_unknown = interface_unknown;
}
static void
handle_pragma_implementation (dfile)
cpp_reader *dfile ATTRIBUTE_UNUSED;
{
tree fname = parse_strconst_pragma ("implementation", 1);
const char *main_filename;
struct impl_files *ifiles = impl_file_chain;
if (fname == (tree)-1)
return;
if (fname == 0)
{
if (main_input_filename)
main_filename = main_input_filename;
else
main_filename = input_filename;
main_filename = lbasename (main_filename);
}
else
{
main_filename = TREE_STRING_POINTER (fname);
if (cpp_included (parse_in, main_filename))
warning ("#pragma implementation for %s appears after file is included",
main_filename);
}
for (; ifiles; ifiles = ifiles->next)
{
if (! strcmp (ifiles->filename, main_filename))
break;
}
if (ifiles == 0)
{
ifiles = (struct impl_files*) xmalloc (sizeof (struct impl_files));
ifiles->filename = main_filename;
ifiles->next = impl_file_chain;
impl_file_chain = ifiles;
}
}
static void
handle_pragma_java_exceptions (dfile)
cpp_reader *dfile ATTRIBUTE_UNUSED;
{
tree x;
if (c_lex (&x) != CPP_EOF)
warning ("junk at end of #pragma GCC java_exceptions");
choose_personality_routine (lang_java);
}
void
do_pending_lang_change ()
{
for (; pending_lang_change > 0; --pending_lang_change)
push_lang_context (lang_name_c);
for (; pending_lang_change < 0; ++pending_lang_change)
pop_lang_context ();
}
static int
is_global (d)
tree d;
{
while (1)
switch (TREE_CODE (d))
{
case ERROR_MARK:
return 1;
case OVERLOAD: d = OVL_FUNCTION (d); continue;
case TREE_LIST: d = TREE_VALUE (d); continue;
default:
my_friendly_assert (DECL_P (d), 980629);
return DECL_NAMESPACE_SCOPE_P (d);
}
}
tree
do_identifier (token, parsing, args)
register tree token;
int parsing;
tree args;
{
tree id;
int lexing = (parsing == 1);
extern int objc_msg_context;
extern int objcp_lookup_identifier PARAMS ((tree, tree *, int));
if (! lexing || objc_msg_context)
id = lookup_name (token, 0);
else
id = lastiddecl;
if (lexing && id && TREE_DEPRECATED (id))
warn_deprecated_use (id);
if (args && !current_template_parms && (!id || is_global (id)))
id = lookup_arg_dependent (token, id, args);
if (id && parsing)
maybe_note_name_used_in_class (token, id);
if (id == error_mark_node)
{
id = lookup_name (token, 0);
return error_mark_node;
}
if (!id || (TREE_CODE (id) == FUNCTION_DECL
&& DECL_ANTICIPATED (id)))
{
if (current_template_parms)
return build_min_nt (LOOKUP_EXPR, token);
else if (IDENTIFIER_OPNAME_P (token))
{
if (token != ansi_opname (ERROR_MARK))
error ("`%D' not defined", token);
id = error_mark_node;
}
else if (objcp_lookup_identifier (token, &id, 0))
;
else if (current_function_decl == 0)
{
error ("`%D' was not declared in this scope", token);
id = error_mark_node;
}
else
{
if (IDENTIFIER_NAMESPACE_VALUE (token) != error_mark_node
|| IDENTIFIER_ERROR_LOCUS (token) != current_function_decl)
{
static int undeclared_variable_notice;
error ("`%D' undeclared (first use this function)", token);
if (! undeclared_variable_notice)
{
error ("(Each undeclared identifier is reported only once for each function it appears in.)");
undeclared_variable_notice = 1;
}
}
id = error_mark_node;
SET_IDENTIFIER_NAMESPACE_VALUE (token, error_mark_node);
SET_IDENTIFIER_ERROR_LOCUS (token, current_function_decl);
}
}
else
objcp_lookup_identifier (token, &id, 1);
if (TREE_CODE (id) == VAR_DECL && DECL_DEAD_FOR_LOCAL (id))
{
tree shadowed = DECL_SHADOWED_FOR_VAR (id);
while (shadowed != NULL_TREE && TREE_CODE (shadowed) == VAR_DECL
&& DECL_DEAD_FOR_LOCAL (shadowed))
shadowed = DECL_SHADOWED_FOR_VAR (shadowed);
if (!shadowed)
shadowed = IDENTIFIER_NAMESPACE_VALUE (DECL_NAME (id));
if (shadowed)
{
if (!DECL_ERROR_REPORTED (id))
{
warning ("name lookup of `%s' changed",
IDENTIFIER_POINTER (token));
cp_warning_at (" matches this `%D' under ISO standard rules",
shadowed);
cp_warning_at (" matches this `%D' under old rules", id);
DECL_ERROR_REPORTED (id) = 1;
}
id = shadowed;
}
else if (!DECL_ERROR_REPORTED (id))
{
DECL_ERROR_REPORTED (id) = 1;
if (TYPE_HAS_NONTRIVIAL_DESTRUCTOR (TREE_TYPE (id)))
{
error ("name lookup of `%s' changed for new ISO `for' scoping",
IDENTIFIER_POINTER (token));
cp_error_at (" cannot use obsolete binding at `%D' because it has a destructor", id);
id = error_mark_node;
}
else
{
pedwarn ("name lookup of `%s' changed for new ISO `for' scoping",
IDENTIFIER_POINTER (token));
cp_pedwarn_at (" using obsolete binding at `%D'", id);
}
}
}
if (TREE_CODE (id) == CONST_DECL)
{
if (IDENTIFIER_CLASS_VALUE (token) == id)
enforce_access (CP_DECL_CONTEXT(id), id);
if (!processing_template_decl || DECL_TEMPLATE_PARM_P (id))
id = DECL_INITIAL (id);
}
else
id = hack_identifier (id, token);
if (current_template_parms
&& (is_overloaded_fn (id)
|| (TREE_CODE (id) == VAR_DECL
&& CP_DECL_CONTEXT (id)
&& TREE_CODE (CP_DECL_CONTEXT (id)) == FUNCTION_DECL)
|| TREE_CODE (id) == PARM_DECL
|| TREE_CODE (id) == RESULT_DECL
|| TREE_CODE (id) == USING_DECL))
id = build_min_nt (LOOKUP_EXPR, token);
return id;
}
tree
do_scoped_id (token, parsing)
tree token;
int parsing;
{
tree id;
if (parsing)
{
id = make_node (CPLUS_BINDING);
if (!qualified_lookup_using_namespace (token, global_namespace, id, 0))
id = NULL_TREE;
else
id = BINDING_VALUE (id);
}
else
id = IDENTIFIER_GLOBAL_VALUE (token);
if (parsing && yychar == YYEMPTY)
yychar = yylex ();
if (!id || (TREE_CODE (id) == FUNCTION_DECL
&& DECL_ANTICIPATED (id)))
{
if (processing_template_decl)
{
id = build_min_nt (LOOKUP_EXPR, token);
LOOKUP_EXPR_GLOBAL (id) = 1;
return id;
}
if (IDENTIFIER_NAMESPACE_VALUE (token) != error_mark_node)
error ("`::%D' undeclared (first use here)", token);
id = error_mark_node;
SET_IDENTIFIER_NAMESPACE_VALUE (token, error_mark_node);
}
else
{
if (TREE_CODE (id) == ADDR_EXPR)
mark_used (TREE_OPERAND (id, 0));
else if (TREE_CODE (id) != OVERLOAD)
mark_used (id);
}
if (TREE_CODE (id) == CONST_DECL && ! processing_template_decl)
{
id = DECL_INITIAL (id);
id = build1 (NOP_EXPR, TREE_TYPE (id), id);
TREE_CONSTANT (id) = 1;
}
if (processing_template_decl)
{
if (is_overloaded_fn (id))
{
id = build_min_nt (LOOKUP_EXPR, token);
LOOKUP_EXPR_GLOBAL (id) = 1;
return id;
}
}
return convert_from_reference (id);
}
tree
identifier_typedecl_value (node)
tree node;
{
tree t, type;
type = IDENTIFIER_TYPE_VALUE (node);
if (type == NULL_TREE)
return NULL_TREE;
if (IDENTIFIER_BINDING (node))
{
t = IDENTIFIER_VALUE (node);
if (t && TREE_CODE (t) == TYPE_DECL && TREE_TYPE (t) == type)
return t;
}
if (IDENTIFIER_NAMESPACE_VALUE (node))
{
t = IDENTIFIER_NAMESPACE_VALUE (node);
if (t && TREE_CODE (t) == TYPE_DECL && TREE_TYPE (t) == type)
return t;
}
if (TYPE_MAIN_DECL (type))
return TYPE_MAIN_DECL (type);
return NULL_TREE;
}
#ifdef GATHER_STATISTICS
typedef enum
{
d_kind,
t_kind,
b_kind,
s_kind,
r_kind,
e_kind,
c_kind,
id_kind,
op_id_kind,
perm_list_kind,
temp_list_kind,
vec_kind,
x_kind,
lang_decl,
lang_type,
all_kinds
} tree_node_kind;
extern int tree_node_counts[];
extern int tree_node_sizes[];
#endif
tree
build_lang_decl (code, name, type)
enum tree_code code;
tree name;
tree type;
{
tree t;
t = build_decl (code, name, type);
retrofit_lang_decl (t);
return t;
}
void
retrofit_lang_decl (t)
tree t;
{
struct lang_decl *ld;
size_t size;
if (CAN_HAVE_FULL_LANG_DECL_P (t))
size = sizeof (struct lang_decl);
else
size = sizeof (struct lang_decl_flags);
ld = (struct lang_decl *) GGC_ALLOC_CLEARED (size, PFE_ALLOC_GGC_LANG_DECL);
DECL_LANG_SPECIFIC (t) = ld;
if (current_lang_name == lang_name_cplusplus)
SET_DECL_LANGUAGE (t, lang_cplusplus);
else if (current_lang_name == lang_name_c)
SET_DECL_LANGUAGE (t, lang_c);
else if (current_lang_name == lang_name_java)
SET_DECL_LANGUAGE (t, lang_java);
else abort ();
#ifdef GATHER_STATISTICS
tree_node_counts[(int)lang_decl] += 1;
tree_node_sizes[(int)lang_decl] += size;
#endif
}
void
copy_lang_decl (node)
tree node;
{
int size;
struct lang_decl *ld;
if (! DECL_LANG_SPECIFIC (node))
return;
if (!CAN_HAVE_FULL_LANG_DECL_P (node))
size = sizeof (struct lang_decl_flags);
else
size = sizeof (struct lang_decl);
ld = (struct lang_decl *) GGC_ALLOC (size, PFE_ALLOC_GGC_LANG_DECL);
memcpy (ld, DECL_LANG_SPECIFIC (node), size);
DECL_LANG_SPECIFIC (node) = ld;
#ifdef GATHER_STATISTICS
tree_node_counts[(int)lang_decl] += 1;
tree_node_sizes[(int)lang_decl] += size;
#endif
}
tree
copy_decl (decl)
tree decl;
{
tree copy;
copy = copy_node (decl);
copy_lang_decl (copy);
return copy;
}
static void
copy_lang_type (node)
tree node;
{
int size;
struct lang_type *lt;
if (! TYPE_LANG_SPECIFIC (node))
return;
size = sizeof (struct lang_type);
lt = ((struct lang_type *) GGC_ALLOC (size, PFE_ALLOC_GGC_LANG_TYPE));
memcpy (lt, TYPE_LANG_SPECIFIC (node), size);
TYPE_LANG_SPECIFIC (node) = lt;
#ifdef GATHER_STATISTICS
tree_node_counts[(int)lang_type] += 1;
tree_node_sizes[(int)lang_type] += size;
#endif
}
tree
copy_type (type)
tree type;
{
tree copy;
copy = copy_node (type);
copy_lang_type (copy);
return copy;
}
tree
cp_make_lang_type (code)
enum tree_code code;
{
register tree t = make_node (code);
if (IS_AGGR_TYPE_CODE (code)
|| code == BOUND_TEMPLATE_TEMPLATE_PARM)
{
struct lang_type *pi;
pi = ((struct lang_type *)
GGC_ALLOC_CLEARED (sizeof (struct lang_type),
PFE_ALLOC_GGC_LANG_TYPE));
TYPE_LANG_SPECIFIC (t) = pi;
#ifdef GATHER_STATISTICS
tree_node_counts[(int)lang_type] += 1;
tree_node_sizes[(int)lang_type] += sizeof (struct lang_type);
#endif
}
if (IS_AGGR_TYPE_CODE (code))
{
SET_CLASSTYPE_INTERFACE_UNKNOWN_X (t, interface_unknown);
CLASSTYPE_INTERFACE_ONLY (t) = interface_only;
build_pointer_type (t);
}
else
TYPE_ALIAS_SET (t) = 0;
if (IS_AGGR_TYPE_CODE (code) || code == TEMPLATE_TYPE_PARM
|| code == BOUND_TEMPLATE_TEMPLATE_PARM
|| code == TYPENAME_TYPE)
TYPE_BINFO (t) = make_binfo (size_zero_node, t, NULL_TREE, NULL_TREE);
return t;
}
tree
make_aggr_type (code)
enum tree_code code;
{
tree t = cp_make_lang_type (code);
if (IS_AGGR_TYPE_CODE (code))
SET_IS_AGGR_TYPE (t, 1);
return t;
}
void
compiler_error VPARAMS ((const char *msg, ...))
{
char buf[1024];
VA_OPEN (ap, msg);
VA_FIXEDARG (ap, const char *, msg);
vsprintf (buf, msg, ap);
VA_CLOSE (ap);
error_with_file_and_line (input_filename, lineno, "%s (compiler error)", buf);
}
int
cp_type_qual_from_rid (rid)
tree rid;
{
if (rid == ridpointers[(int) RID_CONST])
return TYPE_QUAL_CONST;
else if (rid == ridpointers[(int) RID_VOLATILE])
return TYPE_QUAL_VOLATILE;
else if (rid == ridpointers[(int) RID_RESTRICT])
return TYPE_QUAL_RESTRICT;
abort ();
return TYPE_UNQUALIFIED;
}