blob: 1113c15ba9565b902efe6efb97c1ebcfa57fd320 [file] [log] [blame]
/* YACC parser for C++ syntax.
Copyright (C) 1988, 89, 93, 94, 95, 1996 Free Software Foundation, Inc.
Hacked by Michael Tiemann (tiemann@cygnus.com)
This file is part of GNU CC.
GNU CC is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
GNU CC is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GNU CC; see the file COPYING. If not, write to
the Free Software Foundation, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
/* This grammar is based on the GNU CC grammar. */
/* Note: Bison automatically applies a default action of "$$ = $1" for
all derivations; this is applied before the explicit action, if one
is given. Keep this in mind when reading the actions. */
%{
/* Cause the `yydebug' variable to be defined. */
#define YYDEBUG 1
#include "config.h"
#include "system.h"
#include "tree.h"
#include "input.h"
#include "flags.h"
#include "lex.h"
#include "cp-tree.h"
#include "output.h"
#include "except.h"
#include "toplev.h"
/* Since parsers are distinct for each language, put the language string
definition here. (fnf) */
char *language_string = "GNU C++";
extern tree void_list_node;
extern struct obstack permanent_obstack;
extern int end_of_file;
/* Like YYERROR but do call yyerror. */
#define YYERROR1 { yyerror ("syntax error"); YYERROR; }
#define OP0(NODE) (TREE_OPERAND (NODE, 0))
#define OP1(NODE) (TREE_OPERAND (NODE, 1))
/* Contains the statement keyword (if/while/do) to include in an
error message if the user supplies an empty conditional expression. */
static char *cond_stmt_keyword;
static tree empty_parms PROTO((void));
/* Nonzero if we have an `extern "C"' acting as an extern specifier. */
int have_extern_spec;
int used_extern_spec;
/* Cons up an empty parameter list. */
#ifdef __GNUC__
__inline
#endif
static tree
empty_parms ()
{
tree parms;
if (strict_prototype
|| current_class_type != NULL)
parms = void_list_node;
else
parms = NULL_TREE;
return parms;
}
%}
%start program
%union {long itype; tree ttype; char *strtype; enum tree_code code; flagged_type_tree ftype; }
/* All identifiers that are not reserved words
and are not declared typedefs in the current block */
%token IDENTIFIER
/* All identifiers that are declared typedefs in the current block.
In some contexts, they are treated just like IDENTIFIER,
but they can also serve as typespecs in declarations. */
%token TYPENAME
%token SELFNAME
/* A template function. */
%token PFUNCNAME
/* Reserved words that specify storage class.
yylval contains an IDENTIFIER_NODE which indicates which one. */
%token SCSPEC
/* Reserved words that specify type.
yylval contains an IDENTIFIER_NODE which indicates which one. */
%token TYPESPEC
/* Reserved words that qualify type: "const" or "volatile".
yylval contains an IDENTIFIER_NODE which indicates which one. */
%token CV_QUALIFIER
/* Character or numeric constants.
yylval is the node for the constant. */
%token CONSTANT
/* String constants in raw form.
yylval is a STRING_CST node. */
%token STRING
/* "...", used for functions with variable arglists. */
%token ELLIPSIS
/* the reserved words */
/* SCO include files test "ASM", so use something else. */
%token SIZEOF ENUM /* STRUCT UNION */ IF ELSE WHILE DO FOR SWITCH CASE DEFAULT
%token BREAK CONTINUE RETURN GOTO ASM_KEYWORD TYPEOF ALIGNOF
%token SIGOF
%token ATTRIBUTE EXTENSION LABEL
%token REALPART IMAGPART
/* the reserved words... C++ extensions */
%token <ttype> AGGR
%token <ttype> VISSPEC
%token DELETE NEW THIS OPERATOR CXX_TRUE CXX_FALSE
%token NAMESPACE TYPENAME_KEYWORD USING
%token LEFT_RIGHT TEMPLATE
%token TYPEID DYNAMIC_CAST STATIC_CAST REINTERPRET_CAST CONST_CAST
%token <itype> SCOPE
/* Define the operator tokens and their precedences.
The value is an integer because, if used, it is the tree code
to use in the expression made from the operator. */
%left EMPTY /* used to resolve s/r with epsilon */
%left error
/* Add precedence rules to solve dangling else s/r conflict */
%nonassoc IF
%nonassoc ELSE
%left IDENTIFIER PFUNCNAME TYPENAME SELFNAME PTYPENAME SCSPEC TYPESPEC CV_QUALIFIER ENUM AGGR ELLIPSIS TYPEOF SIGOF OPERATOR NSNAME TYPENAME_KEYWORD
%left '{' ',' ';'
%nonassoc THROW
%right <code> ':'
%right <code> ASSIGN '='
%right <code> '?'
%left <code> OROR
%left <code> ANDAND
%left <code> '|'
%left <code> '^'
%left <code> '&'
%left <code> MIN_MAX
%left <code> EQCOMPARE
%left <code> ARITHCOMPARE '<' '>'
%left <code> LSHIFT RSHIFT
%left <code> '+' '-'
%left <code> '*' '/' '%'
%left <code> POINTSAT_STAR DOT_STAR
%right <code> UNARY PLUSPLUS MINUSMINUS '~'
%left HYPERUNARY
%left <ttype> PAREN_STAR_PAREN LEFT_RIGHT
%left <code> POINTSAT '.' '(' '['
%right SCOPE /* C++ extension */
%nonassoc NEW DELETE TRY CATCH
%type <code> unop
%type <ttype> identifier IDENTIFIER TYPENAME CONSTANT expr nonnull_exprlist
%type <ttype> PFUNCNAME maybe_identifier
%type <ttype> paren_expr_or_null nontrivial_exprlist SELFNAME
%type <ttype> expr_no_commas cast_expr unary_expr primary string STRING
%type <ttype> reserved_declspecs boolean.literal
%type <ttype> reserved_typespecquals
%type <ttype> declmods
%type <ttype> SCSPEC TYPESPEC CV_QUALIFIER maybe_cv_qualifier
%type <itype> initdecls notype_initdecls initdcl /* C++ modification */
%type <ttype> init initlist maybeasm maybe_init defarg defarg1
%type <ttype> asm_operands nonnull_asm_operands asm_operand asm_clobbers
%type <ttype> maybe_attribute attributes attribute attribute_list attrib
%type <ttype> any_word
%type <ttype> compstmt implicitly_scoped_stmt
%type <ttype> declarator notype_declarator after_type_declarator
%type <ttype> direct_notype_declarator direct_after_type_declarator
%type <ttype> opt.component_decl_list component_decl_list
%type <ttype> component_decl component_decl_1 components notype_components
%type <ttype> component_declarator component_declarator0 self_reference
%type <ttype> notype_component_declarator notype_component_declarator0
%type <ttype> after_type_component_declarator after_type_component_declarator0
%type <ttype> enumlist enumerator
%type <ttype> absdcl cv_qualifiers
%type <ttype> direct_abstract_declarator conversion_declarator
%type <ttype> new_declarator direct_new_declarator
%type <ttype> xexpr parmlist parms bad_parm
%type <ttype> identifiers_or_typenames
%type <ttype> fcast_or_absdcl regcast_or_absdcl
%type <ttype> expr_or_declarator complex_notype_declarator
%type <ttype> notype_unqualified_id unqualified_id qualified_id
%type <ttype> template_id do_id object_template_id notype_template_declarator
%type <ttype> overqualified_id notype_qualified_id any_id
%type <ttype> complex_direct_notype_declarator functional_cast
%type <ttype> complex_parmlist parms_comma
%type <ttype> namespace_qualifier namespace_using_decl
%type <ftype> type_id new_type_id typed_typespecs typespec typed_declspecs
%type <ftype> typed_declspecs1 type_specifier_seq nonempty_cv_qualifiers
%type <ftype> structsp typespecqual_reserved parm named_parm full_parm
/* C++ extensions */
%token <ttype> PTYPENAME
%token <ttype> PRE_PARSED_FUNCTION_DECL EXTERN_LANG_STRING ALL
%token <ttype> PRE_PARSED_CLASS_DECL DEFARG DEFARG_MARKER
%type <ttype> component_constructor_declarator
%type <ttype> fn.def2 return_id fn.defpen constructor_declarator
%type <itype> ctor_initializer_opt
%type <ttype> named_class_head named_class_head_sans_basetype
%type <ttype> named_complex_class_head_sans_basetype
%type <ttype> unnamed_class_head
%type <ttype> class_head base_class_list
%type <ttype> base_class_access_list
%type <ttype> base_class maybe_base_class_list base_class.1
%type <ttype> exception_specification_opt ansi_raise_identifier ansi_raise_identifiers
%type <ttype> operator_name
%type <ttype> object aggr
%type <itype> new delete .begin_new_placement
/* %type <ttype> primary_no_id */
%type <ttype> nonmomentary_expr maybe_parmlist
%type <itype> initdcl0 notype_initdcl0 member_init_list initdcl0_innards
%type <ttype> template_header template_parm_list template_parm
%type <ttype> template_type_parm template_template_parm
%type <code> template_close_bracket
%type <ttype> template_type template_arg_list template_arg_list_opt
%type <ttype> template_arg
%type <ttype> condition xcond paren_cond_or_null
%type <ttype> type_name nested_name_specifier nested_type ptr_to_mem
%type <ttype> complete_type_name notype_identifier nonnested_type
%type <ttype> complex_type_name nested_name_specifier_1
%type <ttype> new_initializer new_placement
%type <ttype> using_decl
%type <ttype> typename_sub typename_sub0 typename_sub1 typename_sub2
%type <ttype> explicit_template_type
/* in order to recognize aggr tags as defining and thus shadowing. */
%token TYPENAME_DEFN IDENTIFIER_DEFN PTYPENAME_DEFN
%type <ttype> named_class_head_sans_basetype_defn
%type <ttype> identifier_defn IDENTIFIER_DEFN TYPENAME_DEFN PTYPENAME_DEFN
%type <ttype> self_template_type
%token NSNAME
%type <ttype> NSNAME
/* Used in lex.c for parsing pragmas. */
%token END_OF_LINE
/* lex.c and pt.c depend on this being the last token. Define
any new tokens before this one! */
%token END_OF_SAVED_INPUT
%{
/* List of types and structure classes of the current declaration. */
static tree current_declspecs;
/* List of prefix attributes in effect.
Prefix attributes are parsed by the reserved_declspecs and declmods
rules. They create a list that contains *both* declspecs and attrs. */
/* ??? It is not clear yet that all cases where an attribute can now appear in
a declspec list have been updated. */
static tree prefix_attributes;
/* When defining an aggregate, this is the most recent one being defined. */
static tree current_aggr;
/* Tell yyparse how to print a token's value, if yydebug is set. */
#define YYPRINT(FILE,YYCHAR,YYLVAL) yyprint(FILE,YYCHAR,YYLVAL)
extern void yyprint PROTO((FILE *, int, YYSTYPE));
extern tree combine_strings PROTO((tree));
static int
parse_decl(declarator, specs_attrs, attributes, initialized, decl)
tree declarator;
tree specs_attrs;
tree attributes;
int initialized;
tree* decl;
{
int sm;
split_specs_attrs (specs_attrs, &current_declspecs, &prefix_attributes);
if (current_declspecs
&& TREE_CODE (current_declspecs) != TREE_LIST)
current_declspecs = get_decl_list (current_declspecs);
if (have_extern_spec && !used_extern_spec)
{
current_declspecs = decl_tree_cons (NULL_TREE,
get_identifier ("extern"),
current_declspecs);
used_extern_spec = 1;
}
sm = suspend_momentary ();
*decl = start_decl (declarator, current_declspecs, initialized,
attributes, prefix_attributes);
return sm;
}
%}
%%
program:
/* empty */
| extdefs
{ finish_translation_unit (); }
;
/* the reason for the strange actions in this rule
is so that notype_initdecls when reached via datadef
can find a valid list of type and sc specs in $0. */
extdefs:
{ $<ttype>$ = NULL_TREE; }
lang_extdef
{ $<ttype>$ = NULL_TREE; }
| extdefs lang_extdef
{ $<ttype>$ = NULL_TREE; }
;
extdefs_opt:
extdefs
| /* empty */
;
.hush_warning:
{ have_extern_spec = 1;
used_extern_spec = 0;
$<ttype>$ = NULL_TREE; }
;
.warning_ok:
{ have_extern_spec = 0; }
;
extension:
EXTENSION
{ $<itype>$ = pedantic;
pedantic = 0; }
;
asm_keyword:
ASM_KEYWORD
;
lang_extdef:
{ if (pending_lang_change) do_pending_lang_change(); }
extdef
{ if (! toplevel_bindings_p () && ! pseudo_global_level_p())
pop_everything (); }
;
extdef:
fndef eat_saved_input
{ if (pending_inlines) do_pending_inlines (); }
| datadef
{ if (pending_inlines) do_pending_inlines (); }
| template_def
{ if (pending_inlines) do_pending_inlines (); }
| asm_keyword '(' string ')' ';'
{ if (TREE_CHAIN ($3)) $3 = combine_strings ($3);
assemble_asm ($3); }
| extern_lang_string '{' extdefs_opt '}'
{ pop_lang_context (); }
| extern_lang_string .hush_warning fndef .warning_ok eat_saved_input
{ if (pending_inlines) do_pending_inlines ();
pop_lang_context (); }
| extern_lang_string .hush_warning datadef .warning_ok
{ if (pending_inlines) do_pending_inlines ();
pop_lang_context (); }
| NAMESPACE identifier '{'
{ push_namespace ($2); }
extdefs_opt '}'
{ pop_namespace (); }
| NAMESPACE '{'
{ push_namespace (NULL_TREE); }
extdefs_opt '}'
{ pop_namespace (); }
| namespace_alias
| using_decl ';'
{ do_toplevel_using_decl ($1); }
| using_directive
| extension extdef
{ pedantic = $<itype>1; }
;
namespace_alias:
NAMESPACE identifier '='
{ begin_only_namespace_names (); }
any_id ';'
{
end_only_namespace_names ();
if (lastiddecl)
$5 = lastiddecl;
do_namespace_alias ($2, $5);
}
;
using_decl:
USING qualified_id
{ $$ = $2; }
| USING global_scope qualified_id
{ $$ = $3; }
| USING global_scope unqualified_id
{ $$ = $3; }
;
namespace_using_decl:
USING namespace_qualifier identifier
{ $$ = build_parse_node (SCOPE_REF, $2, $3); }
| USING global_scope identifier
{ $$ = build_parse_node (SCOPE_REF, global_namespace, $3); }
| USING global_scope namespace_qualifier identifier
{ $$ = build_parse_node (SCOPE_REF, $3, $4); }
;
using_directive:
USING NAMESPACE
{ begin_only_namespace_names (); }
any_id ';'
{
end_only_namespace_names ();
/* If no declaration was found, the using-directive is
invalid. Since that was not reported, we need the
identifier for the error message. */
if (TREE_CODE ($4) == IDENTIFIER_NODE && lastiddecl)
$4 = lastiddecl;
do_using_directive ($4);
}
;
namespace_qualifier:
NSNAME SCOPE
{
if (TREE_CODE ($$) == IDENTIFIER_NODE)
$$ = lastiddecl;
got_scope = $$;
}
| namespace_qualifier NSNAME SCOPE
{
$$ = $2;
if (TREE_CODE ($$) == IDENTIFIER_NODE)
$$ = lastiddecl;
got_scope = $$;
}
any_id:
unqualified_id
| qualified_id
| global_scope qualified_id
{ $$ = $2; }
| global_scope unqualified_id
{ $$ = $2; }
;
extern_lang_string:
EXTERN_LANG_STRING
{ push_lang_context ($1); }
| extern_lang_string EXTERN_LANG_STRING
{ if (current_lang_name != $2)
cp_error ("use of linkage spec `%D' is different from previous spec `%D'", $2, current_lang_name);
pop_lang_context (); push_lang_context ($2); }
;
template_header:
TEMPLATE '<'
{ begin_template_parm_list (); }
template_parm_list '>'
{ $$ = end_template_parm_list ($4); }
| TEMPLATE '<' '>'
{ begin_specialization();
$$ = NULL_TREE; }
;
template_parm_list:
template_parm
{ $$ = process_template_parm (NULL_TREE, $1); }
| template_parm_list ',' template_parm
{ $$ = process_template_parm ($1, $3); }
;
maybe_identifier:
identifier
{ $$ = $1; }
| /* empty */
{ $$ = NULL_TREE; }
template_type_parm:
aggr maybe_identifier
{ $$ = finish_template_type_parm ($1, $2); }
| TYPENAME_KEYWORD maybe_identifier
{ $$ = finish_template_type_parm (class_type_node, $2); }
;
template_template_parm:
template_header aggr maybe_identifier
{ $$ = finish_template_template_parm ($2, $3); }
;
template_parm:
/* The following rules introduce a new reduce/reduce
conflict on the ',' and '>' input tokens: they are valid
prefixes for a `structsp', which means they could match a
nameless parameter. See 14.6, paragraph 3.
By putting them before the `parm' rule, we get
their match before considering them nameless parameter
declarations. */
template_type_parm
{ $$ = build_tree_list (NULL_TREE, $1); }
| template_type_parm '=' type_id
{ $$ = build_tree_list (groktypename ($3.t), $1); }
| parm
{ $$ = build_tree_list (NULL_TREE, $1.t); }
| parm '=' expr_no_commas %prec ARITHCOMPARE
{ $$ = build_tree_list ($3, $1.t); }
| template_template_parm
{ $$ = build_tree_list (NULL_TREE, $1); }
| template_template_parm '=' template_arg
{
if (TREE_CODE ($3) != TEMPLATE_DECL
&& TREE_CODE ($3) != TEMPLATE_TEMPLATE_PARM
&& TREE_CODE ($3) != TYPE_DECL)
{
error ("invalid default template argument");
$3 = error_mark_node;
}
$$ = build_tree_list ($3, $1);
}
;
template_def:
template_header
extdef
{
if ($1)
end_template_decl ();
else
end_specialization ();
}
| template_header
error %prec EMPTY
{
if ($1)
end_template_decl ();
else
end_specialization ();
}
;
datadef:
nomods_initdecls ';'
| declmods notype_initdecls ';'
{}
| typed_declspecs initdecls ';'
{
note_list_got_semicolon ($1.t);
}
| declmods ';'
{ pedwarn ("empty declaration"); }
| explicit_instantiation ';'
| typed_declspecs ';'
{
tree t, attrs;
split_specs_attrs ($1.t, &t, &attrs);
shadow_tag (t);
note_list_got_semicolon ($1.t);
}
| error ';'
| error '}'
| ';'
;
ctor_initializer_opt:
nodecls
{ $$ = 0; }
| base_init
{ $$ = 1; }
;
maybe_return_init:
/* empty */
| return_init
| return_init ';'
;
eat_saved_input:
/* empty */
| END_OF_SAVED_INPUT
;
fndef:
fn.def1 maybe_return_init ctor_initializer_opt compstmt_or_error
{ finish_function (lineno, (int)$3, 0); }
| fn.def1 maybe_return_init function_try_block
{ }
| fn.def1 maybe_return_init error
{ }
;
constructor_declarator:
nested_name_specifier SELFNAME '('
{ $$ = begin_constructor_declarator ($1, $2); }
parmlist ')' cv_qualifiers exception_specification_opt
{ $$ = make_call_declarator ($<ttype>4, $5, $7, $8); }
| nested_name_specifier SELFNAME LEFT_RIGHT cv_qualifiers exception_specification_opt
{ $$ = begin_constructor_declarator ($1, $2);
$$ = make_call_declarator ($$, empty_parms (), $4, $5);
}
| global_scope nested_name_specifier SELFNAME '('
{ $$ = begin_constructor_declarator ($2, $3); }
parmlist ')' cv_qualifiers exception_specification_opt
{ $$ = make_call_declarator ($<ttype>5, $6, $8, $9); }
| global_scope nested_name_specifier SELFNAME LEFT_RIGHT cv_qualifiers exception_specification_opt
{ $$ = begin_constructor_declarator ($2, $3);
$$ = make_call_declarator ($$, empty_parms (), $5, $6);
}
| nested_name_specifier self_template_type '('
{ $$ = begin_constructor_declarator ($1, $2); }
parmlist ')' cv_qualifiers exception_specification_opt
{ $$ = make_call_declarator ($<ttype>4, $5, $7, $8); }
| nested_name_specifier self_template_type LEFT_RIGHT cv_qualifiers exception_specification_opt
{ $$ = begin_constructor_declarator ($1, $2);
$$ = make_call_declarator ($$, empty_parms (), $4, $5);
}
| global_scope nested_name_specifier self_template_type '('
{ $$ = begin_constructor_declarator ($2, $3); }
parmlist ')' cv_qualifiers exception_specification_opt
{ $$ = make_call_declarator ($<ttype>5, $6, $8, $9); }
| global_scope nested_name_specifier self_template_type LEFT_RIGHT cv_qualifiers exception_specification_opt
{ $$ = begin_constructor_declarator ($2, $3);
$$ = make_call_declarator ($$, empty_parms (), $5, $6);
}
;
fn.def1:
typed_declspecs declarator
{ if (!begin_function_definition ($1.t, $2))
YYERROR1; }
| declmods notype_declarator
{ if (!begin_function_definition ($1, $2))
YYERROR1; }
| notype_declarator
{ if (!begin_function_definition (NULL_TREE, $1))
YYERROR1; }
| declmods constructor_declarator
{ if (!begin_function_definition ($1, $2))
YYERROR1; }
| constructor_declarator
{ if (!begin_function_definition (NULL_TREE, $1))
YYERROR1; }
;
component_constructor_declarator:
SELFNAME '(' parmlist ')' cv_qualifiers exception_specification_opt
{ $$ = make_call_declarator ($1, $3, $5, $6); }
| SELFNAME LEFT_RIGHT cv_qualifiers exception_specification_opt
{ $$ = make_call_declarator ($1, empty_parms (), $3, $4); }
| self_template_type '(' parmlist ')' cv_qualifiers exception_specification_opt
{ $$ = make_call_declarator ($1, $3, $5, $6); }
| self_template_type LEFT_RIGHT cv_qualifiers exception_specification_opt
{ $$ = make_call_declarator ($1, empty_parms (), $3, $4); }
;
/* more C++ complexity. See component_decl for a comment on the
reduce/reduce conflict introduced by these rules. */
fn.def2:
declmods component_constructor_declarator
{ tree specs = strip_attrs ($1);
$$ = start_method (specs, $2);
rest_of_mdef:
if (! $$)
YYERROR1;
if (yychar == YYEMPTY)
yychar = YYLEX;
reinit_parse_for_method (yychar, $$); }
| component_constructor_declarator
{ $$ = start_method (NULL_TREE, $1); goto rest_of_mdef; }
| typed_declspecs declarator
{ tree specs = strip_attrs ($1.t);
$$ = start_method (specs, $2); goto rest_of_mdef; }
| declmods notype_declarator
{ tree specs = strip_attrs ($1);
$$ = start_method (specs, $2); goto rest_of_mdef; }
| notype_declarator
{ $$ = start_method (NULL_TREE, $$); goto rest_of_mdef; }
| declmods constructor_declarator
{ tree specs = strip_attrs ($1);
$$ = start_method (specs, $2); goto rest_of_mdef; }
| constructor_declarator
{ $$ = start_method (NULL_TREE, $$); goto rest_of_mdef; }
;
return_id:
RETURN IDENTIFIER
{
if (! current_function_parms_stored)
store_parm_decls ();
$$ = $2;
}
;
return_init:
return_id maybe_init
{ store_return_init ($<ttype>$, $2); }
| return_id '(' nonnull_exprlist ')'
{ store_return_init ($<ttype>$, $3); }
| return_id LEFT_RIGHT
{ store_return_init ($<ttype>$, NULL_TREE); }
;
base_init:
':' .set_base_init member_init_list
{
if ($3 == 0)
error ("no base initializers given following ':'");
setup_vtbl_ptr ();
/* Always keep the BLOCK node associated with the outermost
pair of curley braces of a function. These are needed
for correct operation of dwarfout.c. */
keep_next_level ();
}
;
.set_base_init:
/* empty */
{
if (! current_function_parms_stored)
store_parm_decls ();
if (DECL_CONSTRUCTOR_P (current_function_decl))
{
/* Make a contour for the initializer list. */
pushlevel (0);
clear_last_expr ();
expand_start_bindings (0);
}
else if (current_class_type == NULL_TREE)
error ("base initializers not allowed for non-member functions");
else if (! DECL_CONSTRUCTOR_P (current_function_decl))
error ("only constructors take base initializers");
}
;
member_init_list:
/* empty */
{ $$ = 0; }
| member_init
{ $$ = 1; }
| member_init_list ',' member_init
| member_init_list error
;
member_init:
'(' nonnull_exprlist ')'
{
if (current_class_name)
pedwarn ("anachronistic old style base class initializer");
expand_member_init (current_class_ref, NULL_TREE, $2);
}
| LEFT_RIGHT
{
if (current_class_name)
pedwarn ("anachronistic old style base class initializer");
expand_member_init (current_class_ref, NULL_TREE, void_type_node);
}
| notype_identifier '(' nonnull_exprlist ')'
{ expand_member_init (current_class_ref, $1, $3); }
| notype_identifier LEFT_RIGHT
{ expand_member_init (current_class_ref, $1, void_type_node); }
| nonnested_type '(' nonnull_exprlist ')'
{ expand_member_init (current_class_ref, $1, $3); }
| nonnested_type LEFT_RIGHT
{ expand_member_init (current_class_ref, $1, void_type_node); }
| typename_sub '(' nonnull_exprlist ')'
{ expand_member_init (current_class_ref, TYPE_MAIN_DECL ($1),
$3); }
| typename_sub LEFT_RIGHT
{ expand_member_init (current_class_ref, TYPE_MAIN_DECL ($1),
void_type_node); }
;
identifier:
IDENTIFIER
| TYPENAME
| SELFNAME
| PTYPENAME
| NSNAME
;
notype_identifier:
IDENTIFIER
| PTYPENAME
| NSNAME %prec EMPTY
;
identifier_defn:
IDENTIFIER_DEFN
| TYPENAME_DEFN
| PTYPENAME_DEFN
;
explicit_instantiation:
TEMPLATE begin_explicit_instantiation typespec ';'
{ do_type_instantiation ($3.t, NULL_TREE);
yyungetc (';', 1); }
end_explicit_instantiation
| TEMPLATE begin_explicit_instantiation typed_declspecs declarator
{ tree specs = strip_attrs ($3.t);
do_decl_instantiation (specs, $4, NULL_TREE); }
end_explicit_instantiation
| TEMPLATE begin_explicit_instantiation notype_declarator
{ do_decl_instantiation (NULL_TREE, $3, NULL_TREE); }
end_explicit_instantiation
| TEMPLATE begin_explicit_instantiation constructor_declarator
{ do_decl_instantiation (NULL_TREE, $3, NULL_TREE); }
end_explicit_instantiation
| SCSPEC TEMPLATE begin_explicit_instantiation typespec ';'
{ do_type_instantiation ($4.t, $1);
yyungetc (';', 1); }
end_explicit_instantiation
| SCSPEC TEMPLATE begin_explicit_instantiation typed_declspecs
declarator
{ tree specs = strip_attrs ($4.t);
do_decl_instantiation (specs, $5, $1); }
end_explicit_instantiation
| SCSPEC TEMPLATE begin_explicit_instantiation notype_declarator
{ do_decl_instantiation (NULL_TREE, $4, $1); }
end_explicit_instantiation
| SCSPEC TEMPLATE begin_explicit_instantiation constructor_declarator
{ do_decl_instantiation (NULL_TREE, $4, $1); }
end_explicit_instantiation
;
begin_explicit_instantiation:
{ begin_explicit_instantiation(); }
end_explicit_instantiation:
{ end_explicit_instantiation(); }
/* The TYPENAME expansions are to deal with use of a template class name as
a template within the class itself, where the template decl is hidden by
a type decl. Got all that? */
template_type:
PTYPENAME '<' template_arg_list_opt template_close_bracket
{
$$ = lookup_template_class ($1, $3, NULL_TREE, NULL_TREE);
if ($$ != error_mark_node)
$$ = TYPE_STUB_DECL ($$);
}
| TYPENAME '<' template_arg_list_opt template_close_bracket
{
$$ = lookup_template_class ($1, $3, NULL_TREE, NULL_TREE);
if ($$ != error_mark_node)
$$ = TYPE_STUB_DECL ($$);
}
| self_template_type
;
self_template_type:
SELFNAME '<' template_arg_list_opt template_close_bracket
{
$$ = lookup_template_class ($1, $3, NULL_TREE, NULL_TREE);
if ($$ != error_mark_node)
$$ = TYPE_STUB_DECL ($$);
}
;
template_close_bracket:
'>'
| RSHIFT
{
/* Handle `Class<Class<Type>>' without space in the `>>' */
pedwarn ("`>>' should be `> >' in template class name");
yyungetc ('>', 1);
}
;
template_arg_list_opt:
/* empty */
{ $$ = NULL_TREE; }
| template_arg_list
;
template_arg_list:
template_arg
{ $$ = build_tree_list (NULL_TREE, $$); }
| template_arg_list ',' template_arg
{ $$ = chainon ($$, build_tree_list (NULL_TREE, $3)); }
;
template_arg:
type_id
{ $$ = groktypename ($1.t); }
| PTYPENAME
{ $$ = lastiddecl; }
| expr_no_commas %prec ARITHCOMPARE
;
unop:
'-'
{ $$ = NEGATE_EXPR; }
| '+'
{ $$ = CONVERT_EXPR; }
| PLUSPLUS
{ $$ = PREINCREMENT_EXPR; }
| MINUSMINUS
{ $$ = PREDECREMENT_EXPR; }
| '!'
{ $$ = TRUTH_NOT_EXPR; }
;
expr:
nontrivial_exprlist
{ $$ = build_x_compound_expr ($$); }
| expr_no_commas
;
paren_expr_or_null:
LEFT_RIGHT
{ error ("ANSI C++ forbids an empty condition for `%s'",
cond_stmt_keyword);
$$ = integer_zero_node; }
| '(' expr ')'
{ $$ = $2; }
;
paren_cond_or_null:
LEFT_RIGHT
{ error ("ANSI C++ forbids an empty condition for `%s'",
cond_stmt_keyword);
$$ = integer_zero_node; }
| '(' condition ')'
{ $$ = $2; }
;
xcond:
/* empty */
{ $$ = NULL_TREE; }
| condition
| error
{ $$ = NULL_TREE; }
;
condition:
type_specifier_seq declarator maybeasm maybe_attribute '='
{ {
tree d;
for (d = getdecls (); d; d = TREE_CHAIN (d))
if (TREE_CODE (d) == TYPE_DECL) {
tree s = TREE_TYPE (d);
if (TREE_CODE (s) == RECORD_TYPE)
cp_error ("definition of class `%T' in condition", s);
else if (TREE_CODE (s) == ENUMERAL_TYPE)
cp_error ("definition of enum `%T' in condition", s);
}
}
current_declspecs = $1.t;
$<itype>5 = suspend_momentary ();
$<ttype>$ = start_decl ($<ttype>2, current_declspecs, 1,
$4, /*prefix_attributes*/ NULL_TREE);
}
init
{
cp_finish_decl ($<ttype>6, $7, $4, 1, LOOKUP_ONLYCONVERTING);
resume_momentary ($<itype>5);
$$ = $<ttype>6;
if (TREE_CODE (TREE_TYPE ($$)) == ARRAY_TYPE)
cp_error ("definition of array `%#D' in condition", $$);
}
| expr
;
compstmtend:
'}'
| maybe_label_decls stmts '}'
| maybe_label_decls stmts error '}'
| maybe_label_decls error '}'
;
already_scoped_stmt:
'{'
{ $<ttype>$ = begin_compound_stmt (1); }
compstmtend
{ finish_compound_stmt (1, $<ttype>2); }
| simple_stmt
;
nontrivial_exprlist:
expr_no_commas ',' expr_no_commas
{ $$ = expr_tree_cons (NULL_TREE, $$,
build_expr_list (NULL_TREE, $3)); }
| expr_no_commas ',' error
{ $$ = expr_tree_cons (NULL_TREE, $$,
build_expr_list (NULL_TREE, error_mark_node)); }
| nontrivial_exprlist ',' expr_no_commas
{ chainon ($$, build_expr_list (NULL_TREE, $3)); }
| nontrivial_exprlist ',' error
{ chainon ($$, build_expr_list (NULL_TREE, error_mark_node)); }
;
nonnull_exprlist:
expr_no_commas
{ $$ = build_expr_list (NULL_TREE, $$); }
| nontrivial_exprlist
;
unary_expr:
primary %prec UNARY
{ $$ = $1; }
/* __extension__ turns off -pedantic for following primary. */
| extension cast_expr %prec UNARY
{ $$ = $2;
pedantic = $<itype>1; }
| '*' cast_expr %prec UNARY
{ $$ = build_x_indirect_ref ($2, "unary *"); }
| '&' cast_expr %prec UNARY
{ $$ = build_x_unary_op (ADDR_EXPR, $2); }
| '~' cast_expr
{ $$ = build_x_unary_op (BIT_NOT_EXPR, $2); }
| unop cast_expr %prec UNARY
{ $$ = finish_unary_op_expr ($1, $2); }
/* Refer to the address of a label as a pointer. */
| ANDAND identifier
{ if (pedantic)
pedwarn ("ANSI C++ forbids `&&'");
$$ = finish_label_address_expr ($2); }
| SIZEOF unary_expr %prec UNARY
{ $$ = expr_sizeof ($2); }
| SIZEOF '(' type_id ')' %prec HYPERUNARY
{ $$ = c_sizeof (groktypename ($3.t)); }
| ALIGNOF unary_expr %prec UNARY
{ $$ = grok_alignof ($2); }
| ALIGNOF '(' type_id ')' %prec HYPERUNARY
{ $$ = c_alignof (groktypename ($3.t));
check_for_new_type ("alignof", $3); }
/* The %prec EMPTY's here are required by the = init initializer
syntax extension; see below. */
| new new_type_id %prec EMPTY
{ $$ = build_new (NULL_TREE, $2.t, NULL_TREE, $1);
check_for_new_type ("new", $2); }
| new new_type_id new_initializer
{ $$ = build_new (NULL_TREE, $2.t, $3, $1);
check_for_new_type ("new", $2); }
| new new_placement new_type_id %prec EMPTY
{ $$ = build_new ($2, $3.t, NULL_TREE, $1);
check_for_new_type ("new", $3); }
| new new_placement new_type_id new_initializer
{ $$ = build_new ($2, $3.t, $4, $1);
check_for_new_type ("new", $3); }
/* The .begin_new_placement in the following rules is
necessary to avoid shift/reduce conflicts that lead to
mis-parsing some expressions. Of course, these constructs
are not really new-placement and it is bogus to call
begin_new_placement. But, the parser cannot always tell at this
point whether the next thing is an expression or a type-id,
so there is nothing we can do. Fortunately,
begin_new_placement does nothing harmful. When we rewrite
the parser, this lossage should be removed, of course. */
| new '(' .begin_new_placement type_id .finish_new_placement
%prec EMPTY
{ $$ = build_new (NULL_TREE, groktypename($4.t),
NULL_TREE, $1);
check_for_new_type ("new", $4); }
| new '(' .begin_new_placement type_id .finish_new_placement
new_initializer
{ $$ = build_new (NULL_TREE, groktypename($4.t), $6, $1);
check_for_new_type ("new", $4); }
| new new_placement '(' .begin_new_placement type_id
.finish_new_placement %prec EMPTY
{ $$ = build_new ($2, groktypename($5.t), NULL_TREE, $1);
check_for_new_type ("new", $5); }
| new new_placement '(' .begin_new_placement type_id
.finish_new_placement new_initializer
{ $$ = build_new ($2, groktypename($5.t), $7, $1);
check_for_new_type ("new", $5); }
| delete cast_expr %prec UNARY
{ $$ = delete_sanity ($2, NULL_TREE, 0, $1); }
| delete '[' ']' cast_expr %prec UNARY
{ $$ = delete_sanity ($4, NULL_TREE, 1, $1);
if (yychar == YYEMPTY)
yychar = YYLEX; }
| delete '[' expr ']' cast_expr %prec UNARY
{ $$ = delete_sanity ($5, $3, 2, $1);
if (yychar == YYEMPTY)
yychar = YYLEX; }
| REALPART cast_expr %prec UNARY
{ $$ = build_x_unary_op (REALPART_EXPR, $2); }
| IMAGPART cast_expr %prec UNARY
{ $$ = build_x_unary_op (IMAGPART_EXPR, $2); }
;
/* Note this rule is not suitable for use in new_placement
since it uses NULL_TREE as the argument to
finish_new_placement. This rule serves only to avoid
reduce/reduce conflicts in unary_expr. See the comments
there on the use of begin/finish_new_placement. */
.finish_new_placement:
')'
{ finish_new_placement (NULL_TREE, $<itype>-1); }
.begin_new_placement:
{ $$ = begin_new_placement (); }
new_placement:
'(' .begin_new_placement nonnull_exprlist ')'
{ $$ = finish_new_placement ($3, $2); }
| '{' .begin_new_placement nonnull_exprlist '}'
{ cp_pedwarn ("old style placement syntax, use () instead");
$$ = finish_new_placement ($3, $2); }
;
new_initializer:
'(' nonnull_exprlist ')'
{ $$ = $2; }
| LEFT_RIGHT
{ $$ = NULL_TREE; }
| '(' typespec ')'
{
cp_error ("`%T' is not a valid expression", $2.t);
$$ = error_mark_node;
}
/* GNU extension so people can use initializer lists. Note that
this alters the meaning of `new int = 1', which was previously
syntactically valid but semantically invalid. */
| '=' init
{
if (pedantic)
pedwarn ("ANSI C++ forbids initialization of new expression with `='");
if (TREE_CODE ($2) != TREE_LIST
&& TREE_CODE ($2) != CONSTRUCTOR)
$$ = build_expr_list (NULL_TREE, $2);
else
$$ = $2;
}
;
/* This is necessary to postpone reduction of `int ((int)(int)(int))'. */
regcast_or_absdcl:
'(' type_id ')' %prec EMPTY
{ $2.t = finish_parmlist (build_tree_list (NULL_TREE, $2.t), 0);
$$ = make_call_declarator (NULL_TREE, $2.t, NULL_TREE, NULL_TREE);
check_for_new_type ("cast", $2); }
| regcast_or_absdcl '(' type_id ')' %prec EMPTY
{ $3.t = finish_parmlist (build_tree_list (NULL_TREE, $3.t), 0);
$$ = make_call_declarator ($$, $3.t, NULL_TREE, NULL_TREE);
check_for_new_type ("cast", $3); }
;
cast_expr:
unary_expr
| regcast_or_absdcl unary_expr %prec UNARY
{ $$ = reparse_absdcl_as_casts ($$, $2); }
| regcast_or_absdcl '{' initlist maybecomma '}' %prec UNARY
{
tree init = build_nt (CONSTRUCTOR, NULL_TREE,
nreverse ($3));
if (pedantic)
pedwarn ("ANSI C++ forbids constructor-expressions");
/* Indicate that this was a GNU C constructor expression. */
TREE_HAS_CONSTRUCTOR (init) = 1;
$$ = reparse_absdcl_as_casts ($$, init);
}
;
expr_no_commas:
cast_expr
/* Handle general members. */
| expr_no_commas POINTSAT_STAR expr_no_commas
{ $$ = build_x_binary_op (MEMBER_REF, $$, $3); }
| expr_no_commas DOT_STAR expr_no_commas
{ $$ = build_m_component_ref ($$, $3); }
| expr_no_commas '+' expr_no_commas
{ $$ = build_x_binary_op ($2, $$, $3); }
| expr_no_commas '-' expr_no_commas
{ $$ = build_x_binary_op ($2, $$, $3); }
| expr_no_commas '*' expr_no_commas
{ $$ = build_x_binary_op ($2, $$, $3); }
| expr_no_commas '/' expr_no_commas
{ $$ = build_x_binary_op ($2, $$, $3); }
| expr_no_commas '%' expr_no_commas
{ $$ = build_x_binary_op ($2, $$, $3); }
| expr_no_commas LSHIFT expr_no_commas
{ $$ = build_x_binary_op ($2, $$, $3); }
| expr_no_commas RSHIFT expr_no_commas
{ $$ = build_x_binary_op ($2, $$, $3); }
| expr_no_commas ARITHCOMPARE expr_no_commas
{ $$ = build_x_binary_op ($2, $$, $3); }
| expr_no_commas '<' expr_no_commas
{ $$ = build_x_binary_op (LT_EXPR, $$, $3); }
| expr_no_commas '>' expr_no_commas
{ $$ = build_x_binary_op (GT_EXPR, $$, $3); }
| expr_no_commas EQCOMPARE expr_no_commas
{ $$ = build_x_binary_op ($2, $$, $3); }
| expr_no_commas MIN_MAX expr_no_commas
{ $$ = build_x_binary_op ($2, $$, $3); }
| expr_no_commas '&' expr_no_commas
{ $$ = build_x_binary_op ($2, $$, $3); }
| expr_no_commas '|' expr_no_commas
{ $$ = build_x_binary_op ($2, $$, $3); }
| expr_no_commas '^' expr_no_commas
{ $$ = build_x_binary_op ($2, $$, $3); }
| expr_no_commas ANDAND expr_no_commas
{ $$ = build_x_binary_op (TRUTH_ANDIF_EXPR, $$, $3); }
| expr_no_commas OROR expr_no_commas
{ $$ = build_x_binary_op (TRUTH_ORIF_EXPR, $$, $3); }
| expr_no_commas '?' xexpr ':' expr_no_commas
{ $$ = build_x_conditional_expr ($$, $3, $5); }
| expr_no_commas '=' expr_no_commas
{ $$ = build_x_modify_expr ($$, NOP_EXPR, $3);
if ($$ != error_mark_node)
C_SET_EXP_ORIGINAL_CODE ($$, MODIFY_EXPR); }
| expr_no_commas ASSIGN expr_no_commas
{ $$ = build_x_modify_expr ($$, $2, $3); }
| THROW
{ $$ = build_throw (NULL_TREE); }
| THROW expr_no_commas
{ $$ = build_throw ($2); }
/* These extensions are not defined. The second arg to build_m_component_ref
is old, build_m_component_ref now does an implicit
build_indirect_ref (x, NULL_PTR) on the second argument.
| object '&' expr_no_commas %prec UNARY
{ $$ = build_m_component_ref ($$, build_x_unary_op (ADDR_EXPR, $3)); }
| object unop expr_no_commas %prec UNARY
{ $$ = build_m_component_ref ($$, build_x_unary_op ($2, $3)); }
| object '(' type_id ')' expr_no_commas %prec UNARY
{ tree type = groktypename ($3.t);
$$ = build_m_component_ref ($$, build_c_cast (type, $5)); }
| object primary_no_id %prec UNARY
{ $$ = build_m_component_ref ($$, $2); }
*/
;
notype_unqualified_id:
'~' see_typename identifier
{ $$ = build_parse_node (BIT_NOT_EXPR, $3); }
| template_id
| operator_name
| IDENTIFIER
| PTYPENAME
| NSNAME %prec EMPTY
;
do_id:
{ $$ = do_identifier ($<ttype>-1, 1, NULL_TREE); }
template_id:
PFUNCNAME '<' do_id template_arg_list_opt template_close_bracket
{ $$ = lookup_template_function ($3, $4); }
| operator_name '<' do_id template_arg_list_opt template_close_bracket
{ $$ = lookup_template_function ($3, $4); }
;
object_template_id:
TEMPLATE identifier '<' template_arg_list_opt template_close_bracket
{ $$ = lookup_template_function ($2, $4); }
| TEMPLATE PFUNCNAME '<' template_arg_list_opt template_close_bracket
{ $$ = lookup_template_function ($2, $4); }
| TEMPLATE operator_name '<' template_arg_list_opt
template_close_bracket
{ $$ = lookup_template_function ($2, $4); }
;
unqualified_id:
notype_unqualified_id
| TYPENAME
| SELFNAME
;
expr_or_declarator:
notype_unqualified_id
| '*' expr_or_declarator %prec UNARY
{ $$ = build_parse_node (INDIRECT_REF, $2); }
| '&' expr_or_declarator %prec UNARY
{ $$ = build_parse_node (ADDR_EXPR, $2); }
| '(' expr_or_declarator ')'
{ $$ = $2; }
;
notype_template_declarator:
IDENTIFIER '<' template_arg_list_opt template_close_bracket
{ $$ = lookup_template_function ($1, $3); }
| NSNAME '<' template_arg_list template_close_bracket
{ $$ = lookup_template_function ($1, $3); }
;
direct_notype_declarator:
complex_direct_notype_declarator
/* This precedence declaration is to prefer this reduce
to the Koenig lookup shift in primary, below. I hate yacc. */
| notype_unqualified_id %prec '('
| notype_template_declarator
| '(' expr_or_declarator ')'
{ $$ = finish_decl_parsing ($2); }
;
primary:
notype_unqualified_id
{
if (TREE_CODE ($1) == BIT_NOT_EXPR)
$$ = build_x_unary_op (BIT_NOT_EXPR, TREE_OPERAND ($1, 0));
else
$$ = finish_id_expr ($1);
}
| CONSTANT
| boolean.literal
| string
{
if (processing_template_decl)
push_obstacks (&permanent_obstack, &permanent_obstack);
$$ = combine_strings ($$);
if (processing_template_decl)
pop_obstacks ();
}
| '(' expr ')'
{ $$ = finish_parenthesized_expr ($2); }
| '(' expr_or_declarator ')'
{ $2 = reparse_decl_as_expr (NULL_TREE, $2);
$$ = finish_parenthesized_expr ($2); }
| '(' error ')'
{ $$ = error_mark_node; }
| '('
{ if (current_function_decl == 0)
{
error ("braced-group within expression allowed only inside a function");
YYERROR;
}
if (pedantic)
pedwarn ("ANSI C++ forbids braced-groups within expressions");
$<ttype>$ = begin_stmt_expr ();
}
compstmt ')'
{ $$ = finish_stmt_expr ($<ttype>2, $3); }
/* Koenig lookup support
We could store lastiddecl in $1 to avoid another lookup,
but that would result in many additional reduce/reduce conflicts. */
| notype_unqualified_id '(' nonnull_exprlist ')'
{ $$ = finish_call_expr ($1, $3, 1); }
| notype_unqualified_id LEFT_RIGHT
{ $$ = finish_call_expr ($1, NULL_TREE, 1); }
| primary '(' nonnull_exprlist ')'
{ $$ = finish_call_expr ($1, $3, 0); }
| primary LEFT_RIGHT
{ $$ = finish_call_expr ($1, NULL_TREE, 0); }
| primary '[' expr ']'
{ $$ = grok_array_decl ($$, $3); }
| primary PLUSPLUS
{ $$ = finish_increment_expr ($1, POSTINCREMENT_EXPR); }
| primary MINUSMINUS
{ $$ = finish_increment_expr ($1, POSTDECREMENT_EXPR); }
/* C++ extensions */
| THIS
{ $$ = finish_this_expr (); }
| CV_QUALIFIER '(' nonnull_exprlist ')'
{
tree type = NULL_TREE;
tree id = $$;
/* This is a C cast in C++'s `functional' notation. */
if ($3 == error_mark_node)
{
$$ = error_mark_node;
break;
}
#if 0
if ($3 == NULL_TREE)
{
error ("cannot cast null list to type `%s'",
IDENTIFIER_POINTER (TYPE_NAME (id)));
$$ = error_mark_node;
break;
}
#endif
#if 0
/* type is not set! (mrs) */
if (type == error_mark_node)
$$ = error_mark_node;
else
#endif
{
if (id == ridpointers[(int) RID_CONST])
type = build_type_variant (integer_type_node, 1, 0);
else if (id == ridpointers[(int) RID_VOLATILE])
type = build_type_variant (integer_type_node, 0, 1);
#if 0
/* should not be able to get here (mrs) */
else if (id == ridpointers[(int) RID_FRIEND])
{
error ("cannot cast expression to `friend' type");
$$ = error_mark_node;
break;
}
#endif
else my_friendly_abort (79);
$$ = build_c_cast (type, build_compound_expr ($3));
}
}
| functional_cast
| DYNAMIC_CAST '<' type_id '>' '(' expr ')'
{ tree type = groktypename ($3.t);
check_for_new_type ("dynamic_cast", $3);
$$ = build_dynamic_cast (type, $6); }
| STATIC_CAST '<' type_id '>' '(' expr ')'
{ tree type = groktypename ($3.t);
check_for_new_type ("static_cast", $3);
$$ = build_static_cast (type, $6); }
| REINTERPRET_CAST '<' type_id '>' '(' expr ')'
{ tree type = groktypename ($3.t);
check_for_new_type ("reinterpret_cast", $3);
$$ = build_reinterpret_cast (type, $6); }
| CONST_CAST '<' type_id '>' '(' expr ')'
{ tree type = groktypename ($3.t);
check_for_new_type ("const_cast", $3);
$$ = build_const_cast (type, $6); }
| TYPEID '(' expr ')'
{ $$ = build_x_typeid ($3); }
| TYPEID '(' type_id ')'
{ tree type = groktypename ($3.t);
check_for_new_type ("typeid", $3);
$$ = get_typeid (TYPE_MAIN_VARIANT (type)); }
| global_scope IDENTIFIER
{ $$ = do_scoped_id ($2, 1); }
| global_scope template_id
{ $$ = $2; }
| global_scope operator_name
{
got_scope = NULL_TREE;
if (TREE_CODE ($2) == IDENTIFIER_NODE)
$$ = do_scoped_id ($2, 1);
else
$$ = $2;
}
| overqualified_id %prec HYPERUNARY
{ $$ = build_offset_ref (OP0 ($$), OP1 ($$)); }
| overqualified_id '(' nonnull_exprlist ')'
{ $$ = finish_globally_qualified_member_call_expr ($1, $3); }
| overqualified_id LEFT_RIGHT
{ $$ = finish_globally_qualified_member_call_expr ($1, NULL_TREE); }
| object object_template_id %prec UNARY
{
$$ = build_x_component_ref ($$, $2, NULL_TREE, 1);
}
| object object_template_id '(' nonnull_exprlist ')'
{ $$ = finish_object_call_expr ($2, $1, $4); }
| object object_template_id LEFT_RIGHT
{ $$ = finish_object_call_expr ($2, $1, NULL_TREE); }
| object unqualified_id %prec UNARY
{ $$ = build_x_component_ref ($$, $2, NULL_TREE, 1); }
| object overqualified_id %prec UNARY
{ if (processing_template_decl)
$$ = build_min_nt (COMPONENT_REF, $1, copy_to_permanent ($2));
else
$$ = build_object_ref ($$, OP0 ($2), OP1 ($2)); }
| object unqualified_id '(' nonnull_exprlist ')'
{ $$ = finish_object_call_expr ($2, $1, $4); }
| object unqualified_id LEFT_RIGHT
{ $$ = finish_object_call_expr ($2, $1, NULL_TREE); }
| object overqualified_id '(' nonnull_exprlist ')'
{ $$ = finish_qualified_object_call_expr ($2, $1, $4); }
| object overqualified_id LEFT_RIGHT
{ $$ = finish_qualified_object_call_expr ($2, $1, NULL_TREE); }
/* p->int::~int() is valid -- 12.4 */
| object '~' TYPESPEC LEFT_RIGHT
{ $$ = finish_pseudo_destructor_call_expr ($1, NULL_TREE, $3); }
| object TYPESPEC SCOPE '~' TYPESPEC LEFT_RIGHT
{ $$ = finish_pseudo_destructor_call_expr ($1, $2, $5); }
| object error
{
$$ = error_mark_node;
}
;
/* Not needed for now.
primary_no_id:
'(' expr ')'
{ $$ = $2; }
| '(' error ')'
{ $$ = error_mark_node; }
| '('
{ if (current_function_decl == 0)
{
error ("braced-group within expression allowed only inside a function");
YYERROR;
}
$<ttype>$ = expand_start_stmt_expr (); }
compstmt ')'
{ if (pedantic)
pedwarn ("ANSI C++ forbids braced-groups within expressions");
$$ = expand_end_stmt_expr ($<ttype>2); }
| primary_no_id '(' nonnull_exprlist ')'
{ $$ = build_x_function_call ($$, $3, current_class_ref); }
| primary_no_id LEFT_RIGHT
{ $$ = build_x_function_call ($$, NULL_TREE, current_class_ref); }
| primary_no_id '[' expr ']'
{ goto do_array; }
| primary_no_id PLUSPLUS
{ $$ = build_x_unary_op (POSTINCREMENT_EXPR, $$); }
| primary_no_id MINUSMINUS
{ $$ = build_x_unary_op (POSTDECREMENT_EXPR, $$); }
| SCOPE IDENTIFIER
{ goto do_scoped_id; }
| SCOPE operator_name
{ if (TREE_CODE ($2) == IDENTIFIER_NODE)
goto do_scoped_id;
goto do_scoped_operator;
}
;
*/
new:
NEW
{ $$ = 0; }
| global_scope NEW
{ got_scope = NULL_TREE; $$ = 1; }
;
delete:
DELETE
{ $$ = 0; }
| global_scope delete
{ got_scope = NULL_TREE; $$ = 1; }
;
boolean.literal:
CXX_TRUE
{ $$ = boolean_true_node; }
| CXX_FALSE
{ $$ = boolean_false_node; }
;
/* Produces a STRING_CST with perhaps more STRING_CSTs chained onto it. */
string:
STRING
| string STRING
{ $$ = chainon ($$, $2); }
;
nodecls:
/* empty */
{
if (! current_function_parms_stored)
store_parm_decls ();
setup_vtbl_ptr ();
/* Always keep the BLOCK node associated with the outermost
pair of curley braces of a function. These are needed
for correct operation of dwarfout.c. */
keep_next_level ();
}
;
object:
primary '.'
{ got_object = TREE_TYPE ($$); }
| primary POINTSAT
{
$$ = build_x_arrow ($$);
got_object = TREE_TYPE ($$);
}
;
decl:
typespec initdecls ';'
{
resume_momentary ($2);
if ($1.t && IS_AGGR_TYPE_CODE (TREE_CODE ($1.t)))
note_got_semicolon ($1.t);
}
| typed_declspecs initdecls ';'
{
resume_momentary ($2);
note_list_got_semicolon ($1.t);
}
| declmods notype_initdecls ';'
{ resume_momentary ($2); }
| typed_declspecs ';'
{
shadow_tag ($1.t);
note_list_got_semicolon ($1.t);
}
| declmods ';'
{ warning ("empty declaration"); }
| extension decl
{ pedantic = $<itype>1; }
;
/* Any kind of declarator (thus, all declarators allowed
after an explicit typespec). */
declarator:
after_type_declarator %prec EMPTY
| notype_declarator %prec EMPTY
;
/* This is necessary to postpone reduction of `int()()()()'. */
fcast_or_absdcl:
LEFT_RIGHT %prec EMPTY
{ $$ = make_call_declarator (NULL_TREE, empty_parms (),
NULL_TREE, NULL_TREE); }
| fcast_or_absdcl LEFT_RIGHT %prec EMPTY
{ $$ = make_call_declarator ($$, empty_parms (), NULL_TREE,
NULL_TREE); }
;
/* ANSI type-id (8.1) */
type_id:
typed_typespecs absdcl
{ $$.t = build_decl_list ($1.t, $2);
$$.new_type_flag = $1.new_type_flag; }
| nonempty_cv_qualifiers absdcl
{ $$.t = build_decl_list ($1.t, $2);
$$.new_type_flag = $1.new_type_flag; }
| typespec absdcl
{ $$.t = build_decl_list (get_decl_list ($1.t), $2);
$$.new_type_flag = $1.new_type_flag; }
| typed_typespecs %prec EMPTY
{ $$.t = build_decl_list ($1.t, NULL_TREE);
$$.new_type_flag = $1.new_type_flag; }
| nonempty_cv_qualifiers %prec EMPTY
{ $$.t = build_decl_list ($1.t, NULL_TREE);
$$.new_type_flag = $1.new_type_flag; }
;
/* Declspecs which contain at least one type specifier or typedef name.
(Just `const' or `volatile' is not enough.)
A typedef'd name following these is taken as a name to be declared.
In the result, declspecs have a non-NULL TREE_VALUE, attributes do not. */
typed_declspecs:
typed_typespecs %prec EMPTY
| typed_declspecs1
;
typed_declspecs1:
declmods typespec
{ $$.t = decl_tree_cons (NULL_TREE, $2.t, $1);
$$.new_type_flag = $2.new_type_flag; }
| typespec reserved_declspecs %prec HYPERUNARY
{ $$.t = decl_tree_cons (NULL_TREE, $1.t, $2);
$$.new_type_flag = $1.new_type_flag; }
| typespec reserved_typespecquals reserved_declspecs
{ $$.t = decl_tree_cons (NULL_TREE, $1.t, chainon ($2, $3));
$$.new_type_flag = $1.new_type_flag; }
| declmods typespec reserved_declspecs
{ $$.t = decl_tree_cons (NULL_TREE, $2.t, chainon ($3, $1));
$$.new_type_flag = $2.new_type_flag; }
| declmods typespec reserved_typespecquals
{ $$.t = decl_tree_cons (NULL_TREE, $2.t, chainon ($3, $1));
$$.new_type_flag = $2.new_type_flag; }
| declmods typespec reserved_typespecquals reserved_declspecs
{ $$.t = decl_tree_cons (NULL_TREE, $2.t,
chainon ($3, chainon ($4, $1)));
$$.new_type_flag = $2.new_type_flag; }
;
reserved_declspecs:
SCSPEC
{ if (extra_warnings)
warning ("`%s' is not at beginning of declaration",
IDENTIFIER_POINTER ($$));
$$ = build_decl_list (NULL_TREE, $$); }
| reserved_declspecs typespecqual_reserved
{ $$ = decl_tree_cons (NULL_TREE, $2.t, $$); }
| reserved_declspecs SCSPEC
{ if (extra_warnings)
warning ("`%s' is not at beginning of declaration",
IDENTIFIER_POINTER ($2));
$$ = decl_tree_cons (NULL_TREE, $2, $$); }
| reserved_declspecs attributes
{ $$ = decl_tree_cons ($2, NULL_TREE, $1); }
| attributes
{ $$ = decl_tree_cons ($1, NULL_TREE, NULL_TREE); }
;
/* List of just storage classes and type modifiers.
A declaration can start with just this, but then it cannot be used
to redeclare a typedef-name.
In the result, declspecs have a non-NULL TREE_VALUE, attributes do not. */
declmods:
nonempty_cv_qualifiers %prec EMPTY
{ $$ = $1.t; TREE_STATIC ($$) = 1; }
| SCSPEC
{ $$ = IDENTIFIER_AS_LIST ($$); }
| declmods CV_QUALIFIER
{ $$ = decl_tree_cons (NULL_TREE, $2, $$);
TREE_STATIC ($$) = 1; }
| declmods SCSPEC
{ if (extra_warnings && TREE_STATIC ($$))
warning ("`%s' is not at beginning of declaration",
IDENTIFIER_POINTER ($2));
$$ = decl_tree_cons (NULL_TREE, $2, $$);
TREE_STATIC ($$) = TREE_STATIC ($1); }
| declmods attributes
{ $$ = decl_tree_cons ($2, NULL_TREE, $1); }
| attributes
{ $$ = decl_tree_cons ($1, NULL_TREE, NULL_TREE); }
;
/* Used instead of declspecs where storage classes are not allowed
(that is, for typenames and structure components).
C++ can takes storage classes for structure components.
Don't accept a typedef-name if anything but a modifier precedes it. */
typed_typespecs:
typespec %prec EMPTY
{ $$.t = get_decl_list ($1.t);
$$.new_type_flag = $1.new_type_flag; }
| nonempty_cv_qualifiers typespec
{ $$.t = decl_tree_cons (NULL_TREE, $2.t, $1.t);
$$.new_type_flag = $2.new_type_flag; }
| typespec reserved_typespecquals
{ $$.t = decl_tree_cons (NULL_TREE, $1.t, $2);
$$.new_type_flag = $1.new_type_flag; }
| nonempty_cv_qualifiers typespec reserved_typespecquals
{ $$.t = decl_tree_cons (NULL_TREE, $2.t, chainon ($3, $1.t));
$$.new_type_flag = $1.new_type_flag; }
;
reserved_typespecquals:
typespecqual_reserved
{ $$ = build_decl_list (NULL_TREE, $1.t); }
| reserved_typespecquals typespecqual_reserved
{ $$ = decl_tree_cons (NULL_TREE, $2.t, $1); }
;
/* A typespec (but not a type qualifier).
Once we have seen one of these in a declaration,
if a typedef name appears then it is being redeclared. */
typespec:
structsp
| TYPESPEC %prec EMPTY
{ $$.t = $1; $$.new_type_flag = 0; }
| complete_type_name
{ $$.t = $1; $$.new_type_flag = 0; }
| TYPEOF '(' expr ')'
{ $$.t = TREE_TYPE ($3);
$$.new_type_flag = 0; }
| TYPEOF '(' type_id ')'
{ $$.t = groktypename ($3.t);
$$.new_type_flag = 0; }
| SIGOF '(' expr ')'
{ tree type = TREE_TYPE ($3);
$$.new_type_flag = 0;
if (IS_AGGR_TYPE (type))
{
sorry ("sigof type specifier");
$$.t = type;
}
else
{
error ("`sigof' applied to non-aggregate expression");
$$.t = error_mark_node;
}
}
| SIGOF '(' type_id ')'
{ tree type = groktypename ($3.t);
$$.new_type_flag = 0;
if (IS_AGGR_TYPE (type))
{
sorry ("sigof type specifier");
$$.t = type;
}
else
{
error("`sigof' applied to non-aggregate type");
$$.t = error_mark_node;
}
}
;
/* A typespec that is a reserved word, or a type qualifier. */
typespecqual_reserved:
TYPESPEC
{ $$.t = $1; $$.new_type_flag = 0; }
| CV_QUALIFIER
{ $$.t = $1; $$.new_type_flag = 0; }
| structsp
;
initdecls:
initdcl0
| initdecls ',' initdcl
;
notype_initdecls:
notype_initdcl0
| notype_initdecls ',' initdcl
;
nomods_initdecls:
nomods_initdcl0
| nomods_initdecls ',' initdcl
;
maybeasm:
/* empty */
{ $$ = NULL_TREE; }
| asm_keyword '(' string ')'
{ if (TREE_CHAIN ($3)) $3 = combine_strings ($3); $$ = $3; }
;
initdcl:
declarator maybeasm maybe_attribute '='
{ $<ttype>$ = start_decl ($<ttype>1, current_declspecs, 1,
$3, prefix_attributes); }
init
/* Note how the declaration of the variable is in effect while its init is parsed! */
{ cp_finish_decl ($<ttype>5, $6, $2, 1, LOOKUP_ONLYCONVERTING); }
| declarator maybeasm maybe_attribute
{ $<ttype>$ = start_decl ($<ttype>1, current_declspecs, 0,
$3, prefix_attributes);
cp_finish_decl ($<ttype>$, NULL_TREE, $2, 1, 0); }
;
/* This rule assumes a certain configuration of the parser stack.
In particular, $0, the element directly before the beginning of
this rule on the stack, must be a maybeasm. $-1 must be a
declarator or notype_declarator. And $-2 must be some declmods
or declspecs. We can't move the maybeasm into this rule because
we need that reduce so we prefer fn.def1 when appropriate. */
initdcl0_innards:
maybe_attribute '='
{ $<itype>2 = parse_decl ($<ttype>-1, $<ttype>-2,
$1, 1, &$<ttype>$); }
/* Note how the declaration of the variable is in effect
while its init is parsed! */
init
{ cp_finish_decl ($<ttype>3, $4, $<ttype>0, 1,
LOOKUP_ONLYCONVERTING);
$$ = $<itype>2; }
| maybe_attribute
{ tree d;
$$ = parse_decl ($<ttype>-1, $<ttype>-2, $1, 0, &d);
cp_finish_decl (d, NULL_TREE, $<ttype>0, 1, 0); }
;
initdcl0:
declarator maybeasm initdcl0_innards
{ $$ = $3; }
notype_initdcl0:
notype_declarator maybeasm initdcl0_innards
{ $$ = $3; }
;
nomods_initdcl0:
notype_declarator maybeasm
{ /* Set things up as initdcl0_innards expects. */
$<ttype>$ = $1;
$1 = NULL_TREE; }
initdcl0_innards
{}
| constructor_declarator maybeasm maybe_attribute
{ tree d;
parse_decl($1, NULL_TREE, $3, 0, &d);
cp_finish_decl (d, NULL_TREE, $2, 1, 0); }
;
/* the * rules are dummies to accept the Apollo extended syntax
so that the header files compile. */
maybe_attribute:
/* empty */
{ $$ = NULL_TREE; }
| attributes
{ $$ = $1; }
;
attributes:
attribute
{ $$ = $1; }
| attributes attribute
{ $$ = chainon ($1, $2); }
;
attribute:
ATTRIBUTE '(' '(' attribute_list ')' ')'
{ $$ = $4; }
;
attribute_list:
attrib
{ $$ = $1; }
| attribute_list ',' attrib
{ $$ = chainon ($1, $3); }
;
attrib:
/* empty */
{ $$ = NULL_TREE; }
| any_word
{ $$ = build_tree_list ($1, NULL_TREE); }
| any_word '(' IDENTIFIER ')'
{ $$ = build_tree_list ($1, build_tree_list (NULL_TREE, $3)); }
| any_word '(' IDENTIFIER ',' nonnull_exprlist ')'
{ $$ = build_tree_list ($1, tree_cons (NULL_TREE, $3, $5)); }
| any_word '(' nonnull_exprlist ')'
{ $$ = build_tree_list ($1, $3); }
;
/* This still leaves out most reserved keywords,
shouldn't we include them? */
any_word:
identifier
| SCSPEC
| TYPESPEC
| CV_QUALIFIER
;
/* A nonempty list of identifiers, including typenames. */
identifiers_or_typenames:
identifier
{ $$ = build_tree_list (NULL_TREE, $1); }
| identifiers_or_typenames ',' identifier
{ $$ = chainon ($1, build_tree_list (NULL_TREE, $3)); }
;
maybe_init:
/* empty */ %prec EMPTY
{ $$ = NULL_TREE; }
| '=' init
{ $$ = $2; }
/* If we are processing a template, we don't want to expand this
initializer yet. */
init:
expr_no_commas %prec '='
| '{' '}'
{ $$ = build_nt (CONSTRUCTOR, NULL_TREE, NULL_TREE);
TREE_HAS_CONSTRUCTOR ($$) = 1; }
| '{' initlist '}'
{ $$ = build_nt (CONSTRUCTOR, NULL_TREE, nreverse ($2));
TREE_HAS_CONSTRUCTOR ($$) = 1; }
| '{' initlist ',' '}'
{ $$ = build_nt (CONSTRUCTOR, NULL_TREE, nreverse ($2));
TREE_HAS_CONSTRUCTOR ($$) = 1; }
| error
{ $$ = NULL_TREE; }
;
/* This chain is built in reverse order,
and put in forward order where initlist is used. */
initlist:
init
{ $$ = build_tree_list (NULL_TREE, $$); }
| initlist ',' init
{ $$ = expr_tree_cons (NULL_TREE, $3, $$); }
/* These are for labeled elements. */
| '[' expr_no_commas ']' init
{ $$ = build_expr_list ($2, $4); }
| identifier ':' init
{ $$ = build_expr_list ($$, $3); }
| initlist ',' identifier ':' init
{ $$ = expr_tree_cons ($3, $5, $$); }
;
fn.defpen:
PRE_PARSED_FUNCTION_DECL
{ start_function (NULL_TREE, TREE_VALUE ($1),
NULL_TREE, 1);
reinit_parse_for_function (); }
pending_inline:
fn.defpen maybe_return_init ctor_initializer_opt compstmt_or_error
{
int nested = (hack_decl_function_context
(current_function_decl) != NULL_TREE);
finish_function (lineno, (int)$3, nested);
process_next_inline ($1);
}
| fn.defpen maybe_return_init function_try_block
{ process_next_inline ($1); }
| fn.defpen maybe_return_init error
{ process_next_inline ($1); }
;
pending_inlines:
/* empty */
| pending_inlines pending_inline eat_saved_input
;
/* A regurgitated default argument. The value of DEFARG_MARKER will be
the TREE_LIST node for the parameter in question. */
defarg_again:
DEFARG_MARKER expr_no_commas END_OF_SAVED_INPUT
{ replace_defarg ($1, $2); }
| DEFARG_MARKER error END_OF_SAVED_INPUT
{ replace_defarg ($1, error_mark_node); }
pending_defargs:
/* empty */ %prec EMPTY
| pending_defargs defarg_again
{ do_pending_defargs (); }
| pending_defargs error
{ do_pending_defargs (); }
;
structsp:
ENUM identifier '{'
{ $<itype>3 = suspend_momentary ();
$<ttype>$ = start_enum ($2); }
enumlist maybecomma_warn '}'
{ $$.t = finish_enum ($<ttype>4, $5);
$$.new_type_flag = 1;
resume_momentary ((int) $<itype>3);
check_for_missing_semicolon ($<ttype>4); }
| ENUM identifier '{' '}'
{ $$.t = finish_enum (start_enum ($2), NULL_TREE);
$$.new_type_flag = 1;
check_for_missing_semicolon ($$.t); }
| ENUM '{'
{ $<itype>2 = suspend_momentary ();
$<ttype>$ = start_enum (make_anon_name ()); }
enumlist maybecomma_warn '}'
{ $$.t = finish_enum ($<ttype>3, $4);
resume_momentary ((int) $<itype>1);
check_for_missing_semicolon ($<ttype>3);
$$.new_type_flag = 1; }
| ENUM '{' '}'
{ $$.t = finish_enum (start_enum (make_anon_name()), NULL_TREE);
$$.new_type_flag = 1;
check_for_missing_semicolon ($$.t); }
| ENUM identifier
{ $$.t = xref_tag (enum_type_node, $2, NULL_TREE, 1);
$$.new_type_flag = 0; }
| ENUM complex_type_name
{ $$.t = xref_tag (enum_type_node, $2, NULL_TREE, 1);
$$.new_type_flag = 0; }
| TYPENAME_KEYWORD typename_sub
{ $$.t = $2;
$$.new_type_flag = 0; }
/* C++ extensions, merged with C to avoid shift/reduce conflicts */
| class_head left_curly
opt.component_decl_list '}' maybe_attribute
{
int semi;
if (yychar == YYEMPTY)
yychar = YYLEX;
semi = yychar == ';';
$<ttype>$ = finish_class_definition ($1, $3, $5, semi);
}
pending_defargs
{ finish_default_args (); }
pending_inlines
{ $$.t = $<ttype>6;
$$.new_type_flag = 1;
begin_inline_definitions (); }
| class_head %prec EMPTY
{
$$.new_type_flag = 0;
if (TYPE_BINFO ($1) == NULL_TREE)
{
cp_error ("%T is not a class type", $1);
$$.t = error_mark_node;
}
else
{
$$.t = $1;
/* struct B: public A; is not accepted by the WP grammar. */
if (TYPE_BINFO_BASETYPES ($$.t) && !TYPE_SIZE ($$.t)
&& ! TYPE_BEING_DEFINED ($$.t))
cp_error ("base clause without member specification for `%#T'",
$$.t);
}
}
;
maybecomma:
/* empty */
| ','
;
maybecomma_warn:
/* empty */
| ','
{ if (pedantic && !in_system_header)
pedwarn ("comma at end of enumerator list"); }
;
aggr:
AGGR
| aggr SCSPEC
{ error ("storage class specifier `%s' not allowed after struct or class", IDENTIFIER_POINTER ($2)); }
| aggr TYPESPEC
{ error ("type specifier `%s' not allowed after struct or class", IDENTIFIER_POINTER ($2)); }
| aggr CV_QUALIFIER
{ error ("type qualifier `%s' not allowed after struct or class", IDENTIFIER_POINTER ($2)); }
| aggr AGGR
{ error ("no body nor ';' separates two class, struct or union declarations"); }
| aggr attributes
{ $$ = build_decl_list ($2, $1); }
;
named_class_head_sans_basetype:
aggr identifier
{ current_aggr = $$; $$ = $2; }
;
named_class_head_sans_basetype_defn:
aggr identifier_defn %prec EMPTY
{ current_aggr = $$; $$ = $2; }
| named_class_head_sans_basetype '{'
{ yyungetc ('{', 1); }
| named_class_head_sans_basetype ':'
{ yyungetc (':', 1); }
;
named_complex_class_head_sans_basetype:
aggr nested_name_specifier identifier
{
current_aggr = $1;
$$ = handle_class_head ($1, $2, $3);
}
| aggr global_scope nested_name_specifier identifier
{
current_aggr = $1;
$$ = handle_class_head ($1, $3, $4);
}
| aggr global_scope identifier
{
current_aggr = $1;
$$ = handle_class_head ($1, NULL_TREE, $3);
}
| aggr template_type
{ current_aggr = $$; $$ = $2; }
| aggr nested_name_specifier template_type
{ current_aggr = $$; $$ = $3; }
;
do_xref_defn:
/* empty */ %prec EMPTY
{ $<ttype>$ = xref_tag (current_aggr, $<ttype>0, NULL_TREE, 0); }
;
named_class_head:
named_class_head_sans_basetype %prec EMPTY
{ $$ = xref_tag (current_aggr, $1, NULL_TREE, 1); }
| named_class_head_sans_basetype_defn do_xref_defn
maybe_base_class_list %prec EMPTY
{
$$ = $<ttype>2;
if ($3)
xref_basetypes (current_aggr, $1, $<ttype>2, $3);
}
| named_complex_class_head_sans_basetype maybe_base_class_list
{
$$ = TREE_TYPE ($1);
if (TREE_INT_CST_LOW (current_aggr) == union_type
&& TREE_CODE ($$) != UNION_TYPE)
cp_pedwarn ("`union' tag used in declaring `%#T'", $$);
else if (TREE_CODE ($$) == UNION_TYPE
&& TREE_INT_CST_LOW (current_aggr) != union_type)
cp_pedwarn ("non-`union' tag used in declaring `%#T'", $$);
if ($2)
{
if (IS_AGGR_TYPE ($$) && CLASSTYPE_USE_TEMPLATE ($$))
{
if (CLASSTYPE_IMPLICIT_INSTANTIATION ($$)
&& TYPE_SIZE ($$) == NULL_TREE)
{
SET_CLASSTYPE_TEMPLATE_SPECIALIZATION ($$);
if (processing_template_decl)
push_template_decl (TYPE_MAIN_DECL ($$));
}
else if (CLASSTYPE_TEMPLATE_INSTANTIATION ($$))
cp_error ("specialization after instantiation of `%T'", $$);
}
xref_basetypes (current_aggr, $1, $$, $2);
}
}
;
unnamed_class_head:
aggr '{'
{ $$ = xref_tag ($$, make_anon_name (), NULL_TREE, 0);
yyungetc ('{', 1); }
;
class_head:
unnamed_class_head
| named_class_head
;
maybe_base_class_list:
/* empty */ %prec EMPTY
{ $$ = NULL_TREE; }
| ':' see_typename %prec EMPTY
{ yyungetc(':', 1); $$ = NULL_TREE; }
| ':' see_typename base_class_list %prec EMPTY
{ $$ = $3; }
;
base_class_list:
base_class
| base_class_list ',' see_typename base_class
{ $$ = chainon ($$, $4); }
;
base_class:
base_class.1
{
tree type;
if ($1 == NULL_TREE)
{
error ("invalid base class");
type = error_mark_node;
}
else
type = TREE_TYPE ($1);
if (! is_aggr_type (type, 1))
$$ = NULL_TREE;
else if (current_aggr == signature_type_node
&& (! type) && (! IS_SIGNATURE (type)))
{
error ("class name not allowed as base signature");
$$ = NULL_TREE;
}
else if (current_aggr == signature_type_node)
{
sorry ("signature inheritance, base type `%s' ignored",
IDENTIFIER_POINTER ($$));
$$ = build_tree_list (access_public_node, type);
}
else if (type && IS_SIGNATURE (type))
{
error ("signature name not allowed as base class");
$$ = NULL_TREE;
}
else
$$ = build_tree_list (access_default_node, type);
}
| base_class_access_list see_typename base_class.1
{
tree type;
if ($3 == NULL_TREE)
{
error ("invalid base class");
type = error_mark_node;
}
else
type = TREE_TYPE ($3);
if (current_aggr == signature_type_node)
error ("access and source specifiers not allowed in signature");
if (! is_aggr_type (type, 1))
$$ = NULL_TREE;
else if (current_aggr == signature_type_node
&& (! type) && (! IS_SIGNATURE (type)))
{
error ("class name not allowed as base signature");
$$ = NULL_TREE;
}
else if (current_aggr == signature_type_node)
{
sorry ("signature inheritance, base type `%s' ignored",
IDENTIFIER_POINTER ($$));
$$ = build_tree_list (access_public_node, type);
}
else if (type && IS_SIGNATURE (type))
{
error ("signature name not allowed as base class");
$$ = NULL_TREE;
}
else
$$ = build_tree_list ($$, type);
}
;
base_class.1:
typename_sub
{ $$ = TYPE_MAIN_DECL ($1); }
| nonnested_type
| SIGOF '(' expr ')'
{
if (current_aggr == signature_type_node)
{
if (IS_AGGR_TYPE (TREE_TYPE ($3)))
{
sorry ("`sigof' as base signature specifier");
$$ = TREE_TYPE ($3);
}
else
{
error ("`sigof' applied to non-aggregate expression");
$$ = error_mark_node;
}
}
else
{
error ("`sigof' in struct or class declaration");
$$ = error_mark_node;
}
}
| SIGOF '(' type_id ')'
{
if (current_aggr == signature_type_node)
{
if (IS_AGGR_TYPE (groktypename ($3.t)))
{
sorry ("`sigof' as base signature specifier");
$$ = groktypename ($3.t);
}
else
{
error ("`sigof' applied to non-aggregate expression");
$$ = error_mark_node;
}
}
else
{
error ("`sigof' in struct or class declaration");
$$ = error_mark_node;
}
}
;
base_class_access_list:
VISSPEC see_typename
| SCSPEC see_typename
{ if ($1 != ridpointers[(int)RID_VIRTUAL])
cp_error ("`%D' access", $1);
$$ = access_default_virtual_node; }
| base_class_access_list VISSPEC see_typename
{
if ($1 != access_default_virtual_node)
error ("multiple access specifiers");
else if ($2 == access_public_node)
$$ = access_public_virtual_node;
else if ($2 == access_protected_node)
$$ = access_protected_virtual_node;
else /* $2 == access_private_node */
$$ = access_private_virtual_node;
}
| base_class_access_list SCSPEC see_typename
{ if ($2 != ridpointers[(int)RID_VIRTUAL])
cp_error ("`%D' access", $2);
else if ($$ == access_public_node)
$$ = access_public_virtual_node;
else if ($$ == access_protected_node)
$$ = access_protected_virtual_node;
else if ($$ == access_private_node)
$$ = access_private_virtual_node;
else
error ("multiple `virtual' specifiers");
}
;
left_curly:
'{'
{ $<ttype>0 = begin_class_definition ($<ttype>0); }
;
self_reference:
/* empty */
{
$$ = build_self_reference ();
}
;
opt.component_decl_list:
self_reference
{ if ($$) $$ = build_tree_list (access_public_node, $$); }
| self_reference component_decl_list
{
if (current_aggr == signature_type_node)
$$ = build_tree_list (access_public_node, $2);
else
$$ = build_tree_list (access_default_node, $2);
if ($1) $$ = tree_cons (access_public_node, $1, $$);
}
| opt.component_decl_list VISSPEC ':' component_decl_list
{
tree visspec = $2;
if (current_aggr == signature_type_node)
{
error ("access specifier not allowed in signature");
visspec = access_public_node;
}
$$ = chainon ($$, build_tree_list (visspec, $4));
}
| opt.component_decl_list VISSPEC ':'
{
if (current_aggr == signature_type_node)
error ("access specifier not allowed in signature");
}
;
/* Note: we no longer warn about the semicolon after a component_decl_list.
ARM $9.2 says that the semicolon is optional, and therefore allowed. */
component_decl_list:
component_decl
{ if ($$ == void_type_node) $$ = NULL_TREE;
}
| component_decl_list component_decl
{ /* In pushdecl, we created a reverse list of names
in this binding level. Make sure that the chain
of what we're trying to add isn't the item itself
(which can happen with what pushdecl's doing). */
if ($2 != NULL_TREE && $2 != void_type_node)
{
if (TREE_CHAIN ($2) != $$)
$$ = chainon ($$, $2);
else
$$ = $2;
}
}
;
component_decl:
component_decl_1 ';'
{ }
| component_decl_1 '}'
{ error ("missing ';' before right brace");
yyungetc ('}', 0); }
/* C++: handle constructors, destructors and inline functions */
/* note that INLINE is like a TYPESPEC */
| fn.def2 ':' /* base_init compstmt */
{ $$ = finish_method ($$); }
| fn.def2 TRY /* base_init compstmt */
{ $$ = finish_method ($$); }
| fn.def2 RETURN /* base_init compstmt */
{ $$ = finish_method ($$); }
| fn.def2 '{' /* nodecls compstmt */
{ $$ = finish_method ($$); }
| ';'
{ $$ = NULL_TREE; }
| extension component_decl
{ $$ = $2;
pedantic = $<itype>1; }
| template_header component_decl
{ $$ = finish_member_template_decl ($1, $2); }
| template_header typed_declspecs ';'
{ $$ = finish_member_class_template ($1, $2.t); }
;
component_decl_1:
/* Do not add a "typed_declspecs declarator" rule here for
speed; we need to call grok_x_components for enums, so the
speedup would be insignificant. */
typed_declspecs components
{ $$ = grok_x_components ($1.t, $2); }
| declmods notype_components
{ $$ = grok_x_components ($1, $2); }
| notype_declarator maybeasm maybe_attribute maybe_init
{ $$ = grokfield ($$, NULL_TREE, $4, $2,
build_tree_list ($3, NULL_TREE)); }
| constructor_declarator maybeasm maybe_attribute maybe_init
{ $$ = grokfield ($$, NULL_TREE, $4, $2,
build_tree_list ($3, NULL_TREE)); }
| ':' expr_no_commas
{ $$ = grokbitfield (NULL_TREE, NULL_TREE, $2); }
| error
{ $$ = NULL_TREE; }
/* These rules introduce a reduce/reduce conflict; in
typedef int foo, bar;
class A {
foo (bar);
};
should "A::foo" be declared as a function or "A::bar" as a data
member? In other words, is "bar" an after_type_declarator or a
parmlist? */
| declmods component_constructor_declarator maybeasm maybe_attribute maybe_init
{ tree specs, attrs;
split_specs_attrs ($1, &specs, &attrs);
$$ = grokfield ($2, specs, $5, $3,
build_tree_list ($4, attrs)); }
| component_constructor_declarator maybeasm maybe_attribute maybe_init
{ $$ = grokfield ($$, NULL_TREE, $4, $2,
build_tree_list ($3, NULL_TREE)); }
| using_decl
{ $$ = do_class_using_decl ($1); }
/* The case of exactly one component is handled directly by component_decl. */
/* ??? Huh? ^^^ */
components:
/* empty: possibly anonymous */
{ $$ = NULL_TREE; }
| component_declarator0
| components ',' component_declarator
{
/* In this context, void_type_node encodes
friends. They have been recorded elsewhere. */
if ($$ == void_type_node)
$$ = $3;
else
$$ = chainon ($$, $3);
}
;
notype_components:
/* empty: possibly anonymous */
{ $$ = NULL_TREE; }
| notype_component_declarator0
| notype_components ',' notype_component_declarator
{
/* In this context, void_type_node encodes
friends. They have been recorded elsewhere. */
if ($$ == void_type_node)
$$ = $3;
else
$$ = chainon ($$, $3);
}
;
component_declarator0:
after_type_component_declarator0
| notype_component_declarator0
;
component_declarator:
after_type_component_declarator
| notype_component_declarator
;
after_type_component_declarator0:
after_type_declarator maybeasm maybe_attribute maybe_init
{ split_specs_attrs ($<ttype>0, &current_declspecs,
&prefix_attributes);
$<ttype>0 = current_declspecs;
$$ = grokfield ($$, current_declspecs, $4, $2,
build_tree_list ($3, prefix_attributes)); }
| TYPENAME ':' expr_no_commas maybe_attribute
{ split_specs_attrs ($<ttype>0, &current_declspecs,
&prefix_attributes);
$<ttype>0 = current_declspecs;
$$ = grokbitfield ($$, current_declspecs, $3);
cplus_decl_attributes ($$, $4, prefix_attributes); }
;
notype_component_declarator0:
notype_declarator maybeasm maybe_attribute maybe_init
{ split_specs_attrs ($<ttype>0, &current_declspecs,
&prefix_attributes);
$<ttype>0 = current_declspecs;
$$ = grokfield ($$, current_declspecs, $4, $2,
build_tree_list ($3, prefix_attributes)); }
| constructor_declarator maybeasm maybe_attribute maybe_init
{ split_specs_attrs ($<ttype>0, &current_declspecs,
&prefix_attributes);
$<ttype>0 = current_declspecs;
$$ = grokfield ($$, current_declspecs, $4, $2,
build_tree_list ($3, prefix_attributes)); }
| IDENTIFIER ':' expr_no_commas maybe_attribute
{ split_specs_attrs ($<ttype>0, &current_declspecs,
&prefix_attributes);
$<ttype>0 = current_declspecs;
$$ = grokbitfield ($$, current_declspecs, $3);
cplus_decl_attributes ($$, $4, prefix_attributes); }
| ':' expr_no_commas maybe_attribute
{ split_specs_attrs ($<ttype>0, &current_declspecs,
&prefix_attributes);
$<ttype>0 = current_declspecs;
$$ = grokbitfield (NULL_TREE, current_declspecs, $2);
cplus_decl_attributes ($$, $3, prefix_attributes); }
;
after_type_component_declarator:
after_type_declarator maybeasm maybe_attribute maybe_init
{ $$ = grokfield ($$, current_declspecs, $4, $2,
build_tree_list ($3, prefix_attributes)); }
| TYPENAME ':' expr_no_commas maybe_attribute
{ $$ = grokbitfield ($$, current_declspecs, $3);
cplus_decl_attributes ($$, $4, prefix_attributes); }
;
notype_component_declarator:
notype_declarator maybeasm maybe_attribute maybe_init
{ $$ = grokfield ($$, current_declspecs, $4, $2,
build_tree_list ($3, prefix_attributes)); }
| IDENTIFIER ':' expr_no_commas maybe_attribute
{ $$ = grokbitfield ($$, current_declspecs, $3);
cplus_decl_attributes ($$, $4, prefix_attributes); }
| ':' expr_no_commas maybe_attribute
{ $$ = grokbitfield (NULL_TREE, current_declspecs, $2);
cplus_decl_attributes ($$, $3, prefix_attributes); }
;
/* We chain the enumerators in reverse order.
Because of the way enums are built, the order is
insignificant. Take advantage of this fact. */
enumlist:
enumerator
| enumlist ',' enumerator
{ TREE_CHAIN ($3) = $$; $$ = $3; }
;
enumerator:
identifier
{ $$ = build_enumerator ($$, NULL_TREE); }
| identifier '=' expr_no_commas
{ $$ = build_enumerator ($$, $3); }
;
/* ANSI new-type-id (5.3.4) */
new_type_id:
type_specifier_seq new_declarator
{ $$.t = build_decl_list ($1.t, $2);
$$.new_type_flag = $1.new_type_flag; }
| type_specifier_seq %prec EMPTY
{ $$.t = build_decl_list ($1.t, NULL_TREE);
$$.new_type_flag = $1.new_type_flag; }
/* GNU extension to allow arrays of arbitrary types with
non-constant dimension. For the use of begin_new_placement
here, see the comments in unary_expr above. */
| '(' .begin_new_placement type_id .finish_new_placement
'[' expr ']'
{
if (pedantic)
pedwarn ("ANSI C++ forbids array dimensions with parenthesized type in new");
$$.t = build_parse_node (ARRAY_REF, TREE_VALUE ($3.t), $6);
$$.t = build_decl_list (TREE_PURPOSE ($3.t), $$.t);
$$.new_type_flag = $3.new_type_flag;
}
;
cv_qualifiers:
/* empty */ %prec EMPTY
{ $$ = NULL_TREE; }
| cv_qualifiers CV_QUALIFIER
{ $$ = decl_tree_cons (NULL_TREE, $2, $$); }
;
nonempty_cv_qualifiers:
CV_QUALIFIER
{ $$.t = IDENTIFIER_AS_LIST ($1);
$$.new_type_flag = 0; }
| nonempty_cv_qualifiers CV_QUALIFIER
{ $$.t = decl_tree_cons (NULL_TREE, $2, $1.t);
$$.new_type_flag = $1.new_type_flag; }
;
/* These rules must follow the rules for function declarations
and component declarations. That way, longer rules are preferred. */
suspend_mom:
/* empty */
{ $<itype>$ = suspend_momentary (); }
/* An expression which will not live on the momentary obstack. */
nonmomentary_expr:
suspend_mom expr
{ resume_momentary ((int) $<itype>1); $$ = $2; }
;
/* An expression which will not live on the momentary obstack. */
maybe_parmlist:
suspend_mom '(' nonnull_exprlist ')'
{ resume_momentary ((int) $<itype>1); $$ = $3; }
| suspend_mom '(' parmlist ')'
{ resume_momentary ((int) $<itype>1); $$ = $3; }
| suspend_mom LEFT_RIGHT
{ resume_momentary ((int) $<itype>1); $$ = empty_parms (); }
| suspend_mom '(' error ')'
{ resume_momentary ((int) $<itype>1); $$ = NULL_TREE; }
;
/* A declarator that is allowed only after an explicit typespec. */
/* may all be followed by prec '.' */
after_type_declarator:
'*' nonempty_cv_qualifiers after_type_declarator %prec UNARY
{ $$ = make_pointer_declarator ($2.t, $3); }
| '&' nonempty_cv_qualifiers after_type_declarator %prec UNARY
{ $$ = make_reference_declarator ($2.t, $3); }
| '*' after_type_declarator %prec UNARY
{ $$ = make_pointer_declarator (NULL_TREE, $2); }
| '&' after_type_declarator %prec UNARY
{ $$ = make_reference_declarator (NULL_TREE, $2); }
| ptr_to_mem cv_qualifiers after_type_declarator
{ tree arg = make_pointer_declarator ($2, $3);
$$ = build_parse_node (SCOPE_REF, $1, arg);
}
| direct_after_type_declarator
;
nonnested_type:
type_name %prec EMPTY
{
if (TREE_CODE ($1) == IDENTIFIER_NODE)
{
$$ = lookup_name ($1, 1);
if (current_class_type
&& TYPE_BEING_DEFINED (current_class_type)
&& ! IDENTIFIER_CLASS_VALUE ($1))
{
/* Remember that this name has been used in the class
definition, as per [class.scope0] */
pushdecl_class_level ($$);
}
}
else
$$ = $1;
}
| global_scope type_name
{
if (TREE_CODE ($2) == IDENTIFIER_NODE)
$$ = IDENTIFIER_GLOBAL_VALUE ($2);
else
$$ = $2;
got_scope = NULL_TREE;
}
;
complete_type_name:
nonnested_type
| nested_type
| global_scope nested_type
{ $$ = $2; }
;
nested_type:
nested_name_specifier type_name %prec EMPTY
{ $$ = get_type_decl ($2); }
;
direct_after_type_declarator:
direct_after_type_declarator maybe_parmlist cv_qualifiers exception_specification_opt %prec '.'
{ $$ = make_call_declarator ($$, $2, $3, $4); }
| direct_after_type_declarator '[' nonmomentary_expr ']'
{ $$ = build_parse_node (ARRAY_REF, $$, $3); }
| direct_after_type_declarator '[' ']'
{ $$ = build_parse_node (ARRAY_REF, $$, NULL_TREE); }
| '(' after_type_declarator ')'
{ $$ = $2; }
| nested_name_specifier type_name %prec EMPTY
{ push_nested_class ($1, 3);
$$ = build_parse_node (SCOPE_REF, $$, $2);
TREE_COMPLEXITY ($$) = current_class_depth; }
| type_name %prec EMPTY
;
/* A declarator allowed whether or not there has been
an explicit typespec. These cannot redeclare a typedef-name. */
notype_declarator:
'*' nonempty_cv_qualifiers notype_declarator %prec UNARY
{ $$ = make_pointer_declarator ($2.t, $3); }
| '&' nonempty_cv_qualifiers notype_declarator %prec UNARY
{ $$ = make_reference_declarator ($2.t, $3); }
| '*' notype_declarator %prec UNARY
{ $$ = make_pointer_declarator (NULL_TREE, $2); }
| '&' notype_declarator %prec UNARY
{ $$ = make_reference_declarator (NULL_TREE, $2); }
| ptr_to_mem cv_qualifiers notype_declarator
{ tree arg = make_pointer_declarator ($2, $3);
$$ = build_parse_node (SCOPE_REF, $1, arg);
}
| direct_notype_declarator
;
complex_notype_declarator:
'*' nonempty_cv_qualifiers notype_declarator %prec UNARY
{ $$ = make_pointer_declarator ($2.t, $3); }
| '&' nonempty_cv_qualifiers notype_declarator %prec UNARY
{ $$ = make_reference_declarator ($2.t, $3); }
| '*' complex_notype_declarator %prec UNARY
{ $$ = make_pointer_declarator (NULL_TREE, $2); }
| '&' complex_notype_declarator %prec UNARY
{ $$ = make_reference_declarator (NULL_TREE, $2); }
| ptr_to_mem cv_qualifiers notype_declarator
{ tree arg = make_pointer_declarator ($2, $3);
$$ = build_parse_node (SCOPE_REF, $1, arg);
}
| complex_direct_notype_declarator
;
complex_direct_notype_declarator:
direct_notype_declarator maybe_parmlist cv_qualifiers exception_specification_opt %prec '.'
{ $$ = make_call_declarator ($$, $2, $3, $4); }
| '(' complex_notype_declarator ')'
{ $$ = $2; }
| direct_notype_declarator '[' nonmomentary_expr ']'
{ $$ = build_parse_node (ARRAY_REF, $$, $3); }
| direct_notype_declarator '[' ']'
{ $$ = build_parse_node (ARRAY_REF, $$, NULL_TREE); }
| notype_qualified_id
{ if (TREE_CODE (OP0 ($1)) == NAMESPACE_DECL)
{
push_decl_namespace (OP0 ($1));
TREE_COMPLEXITY ($1) = -1;
}
else if (OP0 ($1) != current_class_type)
{
push_nested_class (OP0 ($1), 3);
TREE_COMPLEXITY ($1) = current_class_depth;
}
}
| nested_name_specifier notype_template_declarator
{ got_scope = NULL_TREE;
$$ = build_parse_node (SCOPE_REF, $1, $2);
if ($1 != current_class_type)
{
push_nested_class ($1, 3);
TREE_COMPLEXITY ($$) = current_class_depth;
}
}
;
qualified_id:
nested_name_specifier unqualified_id
{ got_scope = NULL_TREE;
$$ = build_parse_node (SCOPE_REF, $$, $2); }
| nested_name_specifier object_template_id
{ got_scope = NULL_TREE;
$$ = build_parse_node (SCOPE_REF, $1, $2); }
;
notype_qualified_id:
nested_name_specifier notype_unqualified_id
{ got_scope = NULL_TREE;
$$ = build_parse_node (SCOPE_REF, $$, $2); }
| nested_name_specifier object_template_id
{ got_scope = NULL_TREE;
$$ = build_parse_node (SCOPE_REF, $1, $2); }
;
overqualified_id:
notype_qualified_id
| global_scope notype_qualified_id
{ $$ = $2; }
;
functional_cast:
typespec '(' nonnull_exprlist ')'
{ $$ = build_functional_cast ($1.t, $3); }
| typespec '(' expr_or_declarator ')'
{ $$ = reparse_decl_as_expr ($1.t, $3); }
| typespec fcast_or_absdcl %prec EMPTY
{ $$ = reparse_absdcl_as_expr ($1.t, $2); }
;
type_name:
TYPENAME
| SELFNAME
| template_type %prec EMPTY
;
nested_name_specifier:
nested_name_specifier_1
| nested_name_specifier nested_name_specifier_1
{ $$ = $2; }
| nested_name_specifier TEMPLATE explicit_template_type SCOPE
{ got_scope = $$ = make_typename_type ($1, $3); }
;
/* Why the @#$%^& do type_name and notype_identifier need to be expanded
inline here?!? (jason) */
nested_name_specifier_1:
TYPENAME SCOPE
{
if (TREE_CODE ($1) == IDENTIFIER_NODE)
{
$$ = lastiddecl;
/* Remember that this name has been used in the class
definition, as per [class.scope0] */
if (current_class_type
&& TYPE_BEING_DEFINED (current_class_type)
&& ! IDENTIFIER_CLASS_VALUE ($1))
pushdecl_class_level ($$);
}
got_scope = $$ = TYPE_MAIN_VARIANT (TREE_TYPE ($$));
}
| SELFNAME SCOPE
{
if (TREE_CODE ($1) == IDENTIFIER_NODE)
$$ = lastiddecl;
got_scope = $$ = TREE_TYPE ($$);
}
| NSNAME SCOPE
{
if (TREE_CODE ($$) == IDENTIFIER_NODE)
$$ = lastiddecl;
got_scope = $$;
}
| template_type SCOPE
{ got_scope = $$ = complete_type (TREE_TYPE ($1)); }
/* These break 'const i;'
| IDENTIFIER SCOPE
{
failed_scope:
cp_error ("`%D' is not an aggregate typedef",
lastiddecl ? lastiddecl : $$);
$$ = error_mark_node;
}
| PTYPENAME SCOPE
{ goto failed_scope; } */
;
typename_sub:
typename_sub0
| global_scope typename_sub0
{ $$ = $2; }
;
typename_sub0:
typename_sub1 identifier %prec EMPTY
{
if (TREE_CODE_CLASS (TREE_CODE ($1)) == 't')
$$ = make_typename_type ($1, $2);
else if (TREE_CODE ($2) == IDENTIFIER_NODE)
cp_error ("`%T' is not a class or namespace", $2);
else
{
$$ = $2;
if (TREE_CODE ($$) == TYPE_DECL)
$$ = TREE_TYPE ($$);
}
}
| typename_sub1 template_type %prec EMPTY
{ $$ = TREE_TYPE ($2); }
| typename_sub1 explicit_template_type %prec EMPTY
{ $$ = make_typename_type ($1, $2); }
| typename_sub1 TEMPLATE explicit_template_type %prec EMPTY
{ $$ = make_typename_type ($1, $3); }
;
typename_sub1:
typename_sub2
{
if (TREE_CODE ($1) == IDENTIFIER_NODE)
cp_error ("`%T' is not a class or namespace", $1);
}
| typename_sub1 typename_sub2
{
if (TREE_CODE_CLASS (TREE_CODE ($1)) == 't')
$$ = make_typename_type ($1, $2);
else if (TREE_CODE ($2) == IDENTIFIER_NODE)
cp_error ("`%T' is not a class or namespace", $2);
else
{
$$ = $2;
if (TREE_CODE ($$) == TYPE_DECL)
$$ = TREE_TYPE ($$);
}
}
| typename_sub1 explicit_template_type SCOPE
{ got_scope = $$ = make_typename_type ($1, $2); }
| typename_sub1 TEMPLATE explicit_template_type SCOPE
{ got_scope = $$ = make_typename_type ($1, $3); }
;
typename_sub2:
TYPENAME SCOPE
{
if (TREE_CODE ($1) != IDENTIFIER_NODE)
$1 = lastiddecl;
/* Retrieve the type for the identifier, which might involve
some computation. */
got_scope = $$ = complete_type (IDENTIFIER_TYPE_VALUE ($1));
if ($$ == error_mark_node)
cp_error ("`%T' is not a class or namespace", $1);
}
| SELFNAME SCOPE
{
if (TREE_CODE ($1) != IDENTIFIER_NODE)
$$ = lastiddecl;
got_scope = $$ = complete_type (TREE_TYPE ($$));
}
| template_type SCOPE
{ got_scope = $$ = complete_type (TREE_TYPE ($$)); }
| PTYPENAME SCOPE
| IDENTIFIER SCOPE
| NSNAME SCOPE
{
if (TREE_CODE ($$) == IDENTIFIER_NODE)
$$ = lastiddecl;
got_scope = $$;
}
;
explicit_template_type:
identifier '<' template_arg_list_opt template_close_bracket
{ $$ = build_min_nt (TEMPLATE_ID_EXPR, $1, $3); }
;
complex_type_name:
global_scope type_name
{
if (TREE_CODE ($2) == IDENTIFIER_NODE)
$$ = IDENTIFIER_GLOBAL_VALUE ($2);
else
$$ = $2;
got_scope = NULL_TREE;
}
| nested_type
| global_scope nested_type
{ $$ = $2; }
;
ptr_to_mem:
nested_name_specifier '*'
{ got_scope = NULL_TREE; }
| global_scope nested_name_specifier '*'
{ $$ = $2; got_scope = NULL_TREE; }
;
/* All uses of explicit global scope must go through this nonterminal so
that got_scope will be set before yylex is called to get the next token. */
global_scope:
SCOPE
{ got_scope = void_type_node; }
;
/* ANSI new-declarator (5.3.4) */
new_declarator:
'*' cv_qualifiers new_declarator
{ $$ = make_pointer_declarator ($2, $3); }
| '*' cv_qualifiers %prec EMPTY
{ $$ = make_pointer_declarator ($2, NULL_TREE); }
| '&' cv_qualifiers new_declarator %prec EMPTY
{ $$ = make_reference_declarator ($2, $3); }
| '&' cv_qualifiers %prec EMPTY
{ $$ = make_reference_declarator ($2, NULL_TREE); }
| ptr_to_mem cv_qualifiers %prec EMPTY
{ tree arg = make_pointer_declarator ($2, NULL_TREE);
$$ = build_parse_node (SCOPE_REF, $1, arg);
}
| ptr_to_mem cv_qualifiers new_declarator
{ tree arg = make_pointer_declarator ($2, $3);
$$ = build_parse_node (SCOPE_REF, $1, arg);
}
| direct_new_declarator %prec EMPTY
;
/* ANSI direct-new-declarator (5.3.4) */
direct_new_declarator:
'[' expr ']'
{ $$ = build_parse_node (ARRAY_REF, NULL_TREE, $2); }
| direct_new_declarator '[' nonmomentary_expr ']'
{ $$ = build_parse_node (ARRAY_REF, $$, $3); }
;
/* ANSI abstract-declarator (8.1) */
absdcl:
'*' nonempty_cv_qualifiers absdcl
{ $$ = make_pointer_declarator ($2.t, $3); }
| '*' absdcl
{ $$ = make_pointer_declarator (NULL_TREE, $2); }
| '*' nonempty_cv_qualifiers %prec EMPTY
{ $$ = make_pointer_declarator ($2.t, NULL_TREE); }
| '*' %prec EMPTY
{ $$ = make_pointer_declarator (NULL_TREE, NULL_TREE); }
| '&' nonempty_cv_qualifiers absdcl
{ $$ = make_reference_declarator ($2.t, $3); }
| '&' absdcl
{ $$ = make_reference_declarator (NULL_TREE, $2); }
| '&' nonempty_cv_qualifiers %prec EMPTY
{ $$ = make_reference_declarator ($2.t, NULL_TREE);