#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) */
%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> 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 <ttype> exception_specification_opt ansi_raise_identifier ansi_raise_identifiers
%type <ttype> operator_name
%type <ttype> object aggr
-%type <itype> new delete
+%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
\f
%{
/* List of types and structure classes of the current declaration. */
-static tree current_declspecs = NULL_TREE;
+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 = NULL_TREE;
+static tree prefix_attributes;
/* When defining an aggregate, this is the most recent one being defined. */
static tree current_aggr;
{ push_namespace (NULL_TREE); }
extdefs_opt '}'
{ pop_namespace (); }
- | NAMESPACE identifier '=' any_id ';'
- { do_namespace_alias ($2, $4); }
+ | namespace_alias
| using_decl ';'
{ do_toplevel_using_decl ($1); }
- | USING NAMESPACE any_id ';'
- {
- /* 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 ($3) == IDENTIFIER_NODE && lastiddecl)
- $3 = lastiddecl;
- do_using_directive ($3);
- }
+ | 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; }
{ $$ = $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
template_arg:
type_id
{ $$ = groktypename ($1.t); }
+ | PTYPENAME
+ { $$ = lastiddecl; }
| expr_no_commas %prec ARITHCOMPARE
;
/* empty */
{ $$ = NULL_TREE; }
| condition
- { $$ = condition_conversion ($$); }
| error
{ $$ = NULL_TREE; }
;
| new new_placement new_type_id new_initializer
{ $$ = build_new ($2, $3.t, $4, $1);
check_for_new_type ("new", $3); }
- | new '(' type_id ')' %prec EMPTY
- { $$ = build_new (NULL_TREE, groktypename($3.t),
+ /* 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", $3); }
- | new '(' type_id ')' new_initializer
- { $$ = build_new (NULL_TREE, groktypename($3.t), $5, $1);
- check_for_new_type ("new", $3); }
- | new new_placement '(' type_id ')' %prec EMPTY
- { $$ = build_new ($2, groktypename($4.t), NULL_TREE, $1);
check_for_new_type ("new", $4); }
- | new new_placement '(' type_id ')' new_initializer
- { $$ = build_new ($2, groktypename($4.t), $6, $1);
+ | 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); }
{ $$ = 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:
- '('
- { $<itype>$ = begin_new_placement (); }
- nonnull_exprlist ')'
- { $$ = finish_new_placement ($3, $<itype>1); }
- | '{'
+ '(' .begin_new_placement nonnull_exprlist ')'
+ { $$ = finish_new_placement ($3, $2); }
+ | '{' .begin_new_placement nonnull_exprlist '}'
{ cp_pedwarn ("old style placement syntax, use () instead");
- $<itype>$ = begin_new_placement (); }
- nonnull_exprlist '}'
- { $$ = finish_new_placement ($3, $<itype>1); }
+ $$ = finish_new_placement ($3, $2); }
;
new_initializer:
;
do_id:
- { $$ = do_identifier ($<ttype>-1, 1); }
+ { $$ = do_identifier ($<ttype>-1, 1, NULL_TREE); }
template_id:
PFUNCNAME '<' do_id template_arg_list_opt template_close_bracket
}
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); }
+ { $$ = finish_call_expr ($1, $3, 0); }
| primary LEFT_RIGHT
- { $$ = finish_call_expr ($1, NULL_TREE); }
+ { $$ = finish_call_expr ($1, NULL_TREE, 0); }
| primary '[' expr ']'
{ $$ = grok_array_decl ($$, $3); }
| primary PLUSPLUS
$$ = 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;
{ 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:
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:
base_class:
base_class.1
{
- tree type = TREE_TYPE ($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
}
| base_class_access_list see_typename base_class.1
{
- tree type = TREE_TYPE ($3);
+ 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))
+ if (! is_aggr_type (type, 1))
$$ = NULL_TREE;
else if (current_aggr == signature_type_node
&& (! type) && (! IS_SIGNATURE (type)))
| template_header component_decl
{ $$ = finish_member_template_decl ($1, $2); }
| template_header typed_declspecs ';'
- {
- note_list_got_semicolon ($2.t);
- grok_x_components ($2.t, NULL_TREE);
- if (TYPE_CONTEXT (TREE_VALUE ($2.t)) != current_class_type)
- /* The component was in fact a friend
- declaration. */
- $2.t = NULL_TREE;
- $$ = finish_member_template_decl ($1, $2.t);
- }
+ { $$ = finish_member_class_template ($1, $2.t); }
;
component_decl_1:
{ $$.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. */
- | '(' type_id ')' '[' expr ']'
+ 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 ($2.t), $5);
- $$.t = build_decl_list (TREE_PURPOSE ($2.t), $$.t);
- $$.new_type_flag = $2.new_type_flag;
+ $$.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;
}
;
| direct_notype_declarator '[' ']'
{ $$ = build_parse_node (ARRAY_REF, $$, NULL_TREE); }
| notype_qualified_id
- { if (OP0 ($$) != current_class_type)
+ { if (TREE_CODE (OP0 ($1)) == NAMESPACE_DECL)
{
- push_nested_class (OP0 ($$), 3);
- TREE_COMPLEXITY ($$) = current_class_depth;
+ 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
&& ! IDENTIFIER_CLASS_VALUE ($1))
pushdecl_class_level ($$);
}
- got_scope = $$ = TREE_TYPE ($$);
+ got_scope = $$ = TYPE_MAIN_VARIANT (TREE_TYPE ($$));
}
| SELFNAME SCOPE
{
| ';'
{ finish_stmt (); }
| try_block
+ | using_directive
+ | namespace_using_decl
+ { do_local_using_decl ($1); }
+ | namespace_alias
;
function_try_block:
ctor_initializer_opt compstmt
{
expand_start_all_catch ();
- expand_start_catch (NULL);
}
handler_seq
{
int nested = (hack_decl_function_context
(current_function_decl) != NULL_TREE);
expand_end_all_catch ();
- expand_end_catch ();
finish_function (lineno, (int)$3, nested);
}
;