/* C++ Parser.
Copyright (C) 2000, 2001, 2002, 2003, 2004,
- 2005, 2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc.
+ 2005, 2007, 2008, 2009, 2010, 2011, 2012 Free Software Foundation, Inc.
Written by Mark Mitchell <mark@codesourcery.com>.
This file is part of GCC.
/* a comma operator */
NIC_COMMA,
/* a call to a constructor */
- NIC_CONSTRUCTOR
+ NIC_CONSTRUCTOR,
+ /* a transaction expression */
+ NIC_TRANSACTION
} non_integral_constant;
/* The various kinds of errors about name-lookup failing. */
RT_INTERATION, /* iteration-statement */
RT_JUMP, /* jump-statement */
RT_CLASS_KEY, /* class-key */
- RT_CLASS_TYPENAME_TEMPLATE /* class, typename, or template */
+ RT_CLASS_TYPENAME_TEMPLATE, /* class, typename, or template */
+ RT_TRANSACTION_ATOMIC, /* __transaction_atomic */
+ RT_TRANSACTION_RELAXED, /* __transaction_relaxed */
+ RT_TRANSACTION_CANCEL /* __transaction_cancel */
} required_token;
/* Prototypes. */
(cp_parser *, bool);
static void cp_parser_using_directive
(cp_parser *);
+static tree cp_parser_alias_declaration
+ (cp_parser *);
static void cp_parser_asm_definition
(cp_parser *);
static void cp_parser_linkage_specification
static void cp_parser_label_declaration
(cp_parser *);
+/* Transactional Memory Extensions */
+
+static tree cp_parser_transaction
+ (cp_parser *, enum rid);
+static tree cp_parser_transaction_expression
+ (cp_parser *, enum rid);
+static bool cp_parser_function_transaction
+ (cp_parser *, enum rid);
+static tree cp_parser_transaction_cancel
+ (cp_parser *);
+
enum pragma_context { pragma_external, pragma_stmt, pragma_compound };
static bool cp_parser_pragma
(cp_parser *, enum pragma_context);
(cp_parser *);
static bool cp_parser_cache_group
(cp_parser *, enum cpp_ttype, unsigned);
+static tree cp_parser_cache_defarg
+ (cp_parser *parser, bool nsdmi);
static void cp_parser_parse_tentatively
(cp_parser *);
static void cp_parser_commit_to_tentative_parse
"explicit",
"friend",
"typedef",
+ "using",
"constexpr",
"__complex",
"__thread"
error ("a call to a constructor "
"cannot appear in a constant-expression");
return true;
+ case NIC_TRANSACTION:
+ error ("a transaction expression "
+ "cannot appear in a constant-expression");
+ return true;
case NIC_THIS:
msg = "this";
break;
return value;
}
+/* Look up a literal operator with the name and the exact arguments. */
+
+static tree
+lookup_literal_operator (tree name, VEC(tree,gc) *args)
+{
+ tree decl, fns;
+ decl = lookup_name (name);
+ if (!decl || !is_overloaded_fn (decl))
+ return error_mark_node;
+
+ for (fns = decl; fns; fns = OVL_NEXT (fns))
+ {
+ unsigned int ix;
+ bool found = true;
+ tree fn = OVL_CURRENT (fns);
+ tree argtypes = NULL_TREE;
+ argtypes = TYPE_ARG_TYPES (TREE_TYPE (fn));
+ if (argtypes != NULL_TREE)
+ {
+ for (ix = 0; ix < VEC_length (tree, args) && argtypes != NULL_TREE;
+ ++ix, argtypes = TREE_CHAIN (argtypes))
+ {
+ tree targ = TREE_VALUE (argtypes);
+ tree tparm = TREE_TYPE (VEC_index (tree, args, ix));
+ bool ptr = TREE_CODE (targ) == POINTER_TYPE;
+ bool arr = TREE_CODE (tparm) == ARRAY_TYPE;
+ if ((ptr || arr || !same_type_p (targ, tparm))
+ && (!ptr || !arr
+ || !same_type_p (TREE_TYPE (targ),
+ TREE_TYPE (tparm))))
+ found = false;
+ }
+ if (found
+ && ix == VEC_length (tree, args)
+ /* May be this should be sufficient_parms_p instead,
+ depending on how exactly should user-defined literals
+ work in presence of default arguments on the literal
+ operator parameters. */
+ && argtypes == void_list_node)
+ return fn;
+ }
+ }
+
+ return error_mark_node;
+}
+
/* Parse a user-defined char constant. Returns a call to a user-defined
literal operator taking the character as an argument. */
static tree
cp_parser_userdef_char_literal (cp_parser *parser)
{
- cp_token *token = NULL;
- tree literal, suffix_id, value;
- tree name, decl;
- tree result;
- VEC(tree,gc) *vec;
-
- token = cp_lexer_consume_token (parser->lexer);
- literal = token->u.value;
- suffix_id = USERDEF_LITERAL_SUFFIX_ID (literal);
- value = USERDEF_LITERAL_VALUE (literal);
- name = cp_literal_operator_id (IDENTIFIER_POINTER (suffix_id));
+ cp_token *token = cp_lexer_consume_token (parser->lexer);
+ tree literal = token->u.value;
+ tree suffix_id = USERDEF_LITERAL_SUFFIX_ID (literal);
+ tree value = USERDEF_LITERAL_VALUE (literal);
+ tree name = cp_literal_operator_id (IDENTIFIER_POINTER (suffix_id));
+ tree decl, result;
/* Build up a call to the user-defined operator */
/* Lookup the name we got back from the id-expression. */
- vec = make_tree_vector ();
- VEC_safe_push (tree, gc, vec, value);
- decl = lookup_function_nonclass (name, vec, /*block_p=*/false);
+ VEC(tree,gc) *args = make_tree_vector ();
+ VEC_safe_push (tree, gc, args, value);
+ decl = lookup_literal_operator (name, args);
if (!decl || decl == error_mark_node)
{
- error ("unable to find user-defined character literal operator %qD",
- name);
- release_tree_vector (vec);
+ error ("unable to find character literal operator %qD with %qT argument",
+ name, TREE_TYPE (value));
+ release_tree_vector (args);
return error_mark_node;
}
- result = finish_call_expr (decl, &vec, false, true, tf_warning_or_error);
- release_tree_vector (vec);
+ result = finish_call_expr (decl, &args, false, true, tf_warning_or_error);
+ release_tree_vector (args);
+ if (result != error_mark_node)
+ return result;
- return result;
+ error ("unable to find character literal operator %qD with %qT argument",
+ name, TREE_TYPE (value));
+ return error_mark_node;
}
/* A subroutine of cp_parser_userdef_numeric_literal to
static tree
cp_parser_userdef_numeric_literal (cp_parser *parser)
{
- cp_token *token = NULL;
- tree literal, suffix_id, value, num_string;
- tree name, decl;
- tree result = error_mark_node;
+ cp_token *token = cp_lexer_consume_token (parser->lexer);
+ tree literal = token->u.value;
+ tree suffix_id = USERDEF_LITERAL_SUFFIX_ID (literal);
+ tree value = USERDEF_LITERAL_VALUE (literal);
+ tree num_string = USERDEF_LITERAL_NUM_STRING (literal);
+ tree name = cp_literal_operator_id (IDENTIFIER_POINTER (suffix_id));
+ tree decl, result;
VEC(tree,gc) *args;
- token = cp_lexer_consume_token (parser->lexer);
- literal = token->u.value;
- suffix_id = USERDEF_LITERAL_SUFFIX_ID (literal);
- value = USERDEF_LITERAL_VALUE (literal);
- num_string = USERDEF_LITERAL_NUM_STRING (literal);
- name = cp_literal_operator_id (IDENTIFIER_POINTER (suffix_id));
-
- /* Build up a call to the user-defined operator */
- /* Lookup the name we got back from the id-expression. */
- /* Try to find the literal operator by finishing the call expression
- with the numeric argument. */
+ /* Look for a literal operator taking the exact type of numeric argument
+ as the literal value. */
args = make_tree_vector ();
VEC_safe_push (tree, gc, args, value);
- decl = lookup_function_nonclass (name, args, /*block_p=*/false);
+ decl = lookup_literal_operator (name, args);
if (decl && decl != error_mark_node)
{
result = finish_call_expr (decl, &args, false, true, tf_none);
in string format. */
args = make_tree_vector ();
VEC_safe_push (tree, gc, args, num_string);
- decl = lookup_function_nonclass (name, args, /*block_p=*/false);
+ decl = lookup_literal_operator (name, args);
if (decl && decl != error_mark_node)
{
result = finish_call_expr (decl, &args, false, true, tf_none);
function with parameter pack char.... Call the function with
template parameter characters representing the number. */
args = make_tree_vector ();
- decl = lookup_function_nonclass (name, args, /*block_p=*/false);
+ decl = lookup_literal_operator (name, args);
if (decl && decl != error_mark_node)
{
tree tmpl_args = make_char_string_pack (num_string);
}
release_tree_vector (args);
- if (result == error_mark_node)
- error ("unable to find user-defined numeric literal operator %qD", name);
-
- return result;
+ error ("unable to find numeric literal operator %qD", name);
+ return error_mark_node;
}
/* Parse a user-defined string constant. Returns a call to a user-defined
static tree
cp_parser_userdef_string_literal (cp_token *token)
{
- tree literal, suffix_id, value;
- tree name, decl;
- tree result;
- VEC(tree,gc) *vec;
- int len;
-
- literal = token->u.value;
- suffix_id = USERDEF_LITERAL_SUFFIX_ID (literal);
- name = cp_literal_operator_id (IDENTIFIER_POINTER (suffix_id));
- value = USERDEF_LITERAL_VALUE (literal);
- len = TREE_STRING_LENGTH (value) - 1;
+ tree literal = token->u.value;
+ tree suffix_id = USERDEF_LITERAL_SUFFIX_ID (literal);
+ tree name = cp_literal_operator_id (IDENTIFIER_POINTER (suffix_id));
+ tree value = USERDEF_LITERAL_VALUE (literal);
+ int len = TREE_STRING_LENGTH (value)
+ / TREE_INT_CST_LOW (TYPE_SIZE_UNIT (TREE_TYPE (TREE_TYPE (value)))) - 1;
+ tree decl, result;
/* Build up a call to the user-defined operator */
/* Lookup the name we got back from the id-expression. */
- vec = make_tree_vector ();
- VEC_safe_push (tree, gc, vec, value);
- VEC_safe_push (tree, gc, vec, build_int_cst (size_type_node, len));
- decl = lookup_function_nonclass (name, vec, /*block_p=*/false);
+ VEC(tree,gc) *args = make_tree_vector ();
+ VEC_safe_push (tree, gc, args, value);
+ VEC_safe_push (tree, gc, args, build_int_cst (size_type_node, len));
+ decl = lookup_name (name);
if (!decl || decl == error_mark_node)
{
- error ("unable to find user-defined string literal operator %qD", name);
- release_tree_vector (vec);
+ error ("unable to find string literal operator %qD", name);
+ release_tree_vector (args);
return error_mark_node;
}
- result = finish_call_expr (decl, &vec, false, true, tf_none);
- if (result == error_mark_node)
- error ("unable to find valid user-defined string literal operator %qD."
- " Possible missing length argument in string literal operator.",
- name);
- release_tree_vector (vec);
+ result = finish_call_expr (decl, &args, false, true, tf_none);
+ release_tree_vector (args);
+ if (result != error_mark_node)
+ return result;
- return result;
+ error ("unable to find string literal operator %qD with %qT, %qT arguments",
+ name, TREE_TYPE (value), size_type_node);
+ return error_mark_node;
}
__is_convertible_to ( type-id , type-id )
__is_empty ( type-id )
__is_enum ( type-id )
+ __is_final ( type-id )
__is_literal_type ( type-id )
__is_pod ( type-id )
__is_polymorphic ( type-id )
case RID_IS_CONVERTIBLE_TO:
case RID_IS_EMPTY:
case RID_IS_ENUM:
+ case RID_IS_FINAL:
case RID_IS_LITERAL_TYPE:
case RID_IS_POD:
case RID_IS_POLYMORPHIC:
this is either a class-name or a namespace-name (which corresponds
to the class-or-namespace-name production in the grammar). For
C++0x, it can also be a type-name that refers to an enumeration
- type.
+ type or a simple-template-id.
TYPENAME_KEYWORD_P is TRUE iff the `typename' keyword is in effect.
TEMPLATE_KEYWORD_P is TRUE iff the `template' keyword is in effect.
/* Parse tentatively. */
cp_parser_parse_tentatively (parser);
- /* Parse a typedef-name or enum-name. */
- scope = cp_parser_nonclass_name (parser);
+ /* Parse a type-name */
+ scope = cp_parser_type_name (parser);
/* "If the name found does not designate a namespace or a class,
enumeration, or dependent type, the program is ill-formed."
by cp_parser_builtin_offsetof. We're looking for
postfix-expression [ expression ]
+ postfix-expression [ braced-init-list ] (C++11)
FOR_OFFSETOF is set if we're being called in that context, which
changes how we deal with integer constant expressions. */
if (for_offsetof)
index = cp_parser_constant_expression (parser, false, NULL);
else
- index = cp_parser_expression (parser, /*cast_p=*/false, NULL);
+ {
+ if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_BRACE))
+ {
+ bool expr_nonconst_p;
+ maybe_warn_cpp0x (CPP0X_INITIALIZER_LISTS);
+ index = cp_parser_braced_list (parser, &expr_nonconst_p);
+ }
+ else
+ index = cp_parser_expression (parser, /*cast_p=*/false, NULL);
+ }
/* Look for the closing `]'. */
cp_parser_require (parser, CPP_CLOSE_SQUARE, RT_CLOSE_SQUARE);
{
if (name != error_mark_node && !BASELINK_P (name) && parser->scope)
{
- name = build_qualified_name (/*type=*/NULL_TREE,
- parser->scope,
- name,
- template_p);
+ if (TREE_CODE (parser->scope) == NAMESPACE_DECL)
+ {
+ error_at (token->location, "%<%D::%D%> is not a class member",
+ parser->scope, name);
+ postfix_expression = error_mark_node;
+ }
+ else
+ name = build_qualified_name (/*type=*/NULL_TREE,
+ parser->scope,
+ name,
+ template_p);
parser->scope = NULL_TREE;
parser->qualifying_scope = NULL_TREE;
parser->object_scope = NULL_TREE;
}
- if (scope && name && BASELINK_P (name))
+ if (parser->scope && name && BASELINK_P (name))
adjust_result_of_qualified_name_lookup
- (name, BINFO_TYPE (BASELINK_ACCESS_BINFO (name)), scope);
+ (name, parser->scope, scope);
postfix_expression
= finish_class_member_access_expr (postfix_expression, name,
template_p,
}
break;
+ case RID_TRANSACTION_ATOMIC:
+ case RID_TRANSACTION_RELAXED:
+ return cp_parser_transaction_expression (parser, keyword);
+
case RID_NOEXCEPT:
{
tree expr;
if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_PAREN))
{
cp_token *token;
+ const char *saved_message = parser->type_definition_forbidden_message;
+
/* Consume the `('. */
cp_lexer_consume_token (parser->lexer);
+
/* Parse the type-id. */
+ parser->type_definition_forbidden_message
+ = G_("types may not be defined in a new-expression");
type = cp_parser_type_id (parser);
+ parser->type_definition_forbidden_message = saved_message;
+
/* Look for the closing `)'. */
cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN);
token = cp_lexer_peek_token (parser->lexer);
lhs = cp_parser_cast_expression (parser, /*address_p=*/false, cast_p, pidk);
lhs_type = ERROR_MARK;
+ if (cp_parser_error_occurred (parser))
+ return error_mark_node;
+
for (;;)
{
/* Get an operator token. */
case RID_IS_ENUM:
kind = CPTK_IS_ENUM;
break;
+ case RID_IS_FINAL:
+ kind = CPTK_IS_FINAL;
+ break;
case RID_IS_LITERAL_TYPE:
kind = CPTK_IS_LITERAL_TYPE;
break;
cp_parser_lambda_introducer (parser, lambda_expr);
type = begin_lambda_type (lambda_expr);
+ if (type == error_mark_node)
+ return error_mark_node;
record_lambda_scope (lambda_expr);
declaration-statement
try-block
+ TM Extension:
+
+ statement:
+ atomic-statement
+
IN_COMPOUND is true when the statement is nested inside a
cp_parser_compound_statement; this matters for certain pragmas.
cp_parser_declaration_statement (parser);
return;
+ case RID_TRANSACTION_ATOMIC:
+ case RID_TRANSACTION_RELAXED:
+ statement = cp_parser_transaction (parser, keyword);
+ break;
+ case RID_TRANSACTION_CANCEL:
+ statement = cp_parser_transaction_cancel (parser);
+ break;
+
default:
/* It might be a keyword like `int' that can start a
declaration-statement. */
at instantiation. If not, it is done just ahead. */
if (processing_template_decl)
{
+ if (check_for_bare_parameter_packs (range_expr))
+ range_expr = error_mark_node;
stmt = begin_range_for_stmt (scope, init);
finish_range_for_decl (stmt, range_decl, range_expr);
if (!type_dependent_expression_p (range_expr)
id_begin = get_identifier ("begin");
id_end = get_identifier ("end");
member_begin = lookup_member (TREE_TYPE (range), id_begin,
- /*protect=*/2, /*want_type=*/false);
+ /*protect=*/2, /*want_type=*/false,
+ tf_warning_or_error);
member_end = lookup_member (TREE_TYPE (range), id_end,
- /*protect=*/2, /*want_type=*/false);
+ /*protect=*/2, /*want_type=*/false,
+ tf_warning_or_error);
if (member_begin != NULL_TREE || member_end != NULL_TREE)
{
namespace-alias-definition. */
else if (token1->keyword == RID_NAMESPACE)
cp_parser_namespace_alias_definition (parser);
- /* If the next keyword is `using', we have either a
- using-declaration or a using-directive. */
+ /* If the next keyword is `using', we have a
+ using-declaration, a using-directive, or an alias-declaration. */
else if (token1->keyword == RID_USING)
{
cp_token *token2;
token2 = cp_lexer_peek_nth_token (parser->lexer, 2);
if (token2->keyword == RID_NAMESPACE)
cp_parser_using_directive (parser);
+ /* If the second token after 'using' is '=', then we have an
+ alias-declaration. */
+ else if (cxx_dialect >= cxx0x
+ && token2->type == CPP_NAME
+ && ((cp_lexer_peek_nth_token (parser->lexer, 3)->type == CPP_EQ)
+ || (cp_lexer_peek_nth_token (parser->lexer, 3)->keyword
+ == RID_ATTRIBUTE)))
+ cp_parser_alias_declaration (parser);
/* Otherwise, it's a using-declaration. */
else
cp_parser_using_declaration (parser,
cp_parser_mem_initializer_list (cp_parser* parser)
{
tree mem_initializer_list = NULL_TREE;
+ tree target_ctor = error_mark_node;
cp_token *token = cp_lexer_peek_token (parser->lexer);
/* Let the semantic analysis code know that we are starting the
if (mem_initializer != error_mark_node)
mem_initializer = make_pack_expansion (mem_initializer);
}
+ if (target_ctor != error_mark_node
+ && mem_initializer != error_mark_node)
+ {
+ error ("mem-initializer for %qD follows constructor delegation",
+ TREE_PURPOSE (mem_initializer));
+ mem_initializer = error_mark_node;
+ }
+ /* Look for a target constructor. */
+ if (mem_initializer != error_mark_node
+ && TYPE_P (TREE_PURPOSE (mem_initializer))
+ && same_type_p (TREE_PURPOSE (mem_initializer), current_class_type))
+ {
+ maybe_warn_cpp0x (CPP0X_DELEGATING_CTORS);
+ if (mem_initializer_list)
+ {
+ error ("constructor delegation follows mem-initializer for %qD",
+ TREE_PURPOSE (mem_initializer_list));
+ mem_initializer = error_mark_node;
+ }
+ target_ctor = mem_initializer;
+ }
/* Add it to the list, unless it was erroneous. */
if (mem_initializer != error_mark_node)
{
/* Build a representation of the specialization. */
if (TREE_CODE (templ) == IDENTIFIER_NODE)
template_id = build_min_nt (TEMPLATE_ID_EXPR, templ, arguments);
- else if (DECL_CLASS_TEMPLATE_P (templ)
+ else if (DECL_TYPE_TEMPLATE_P (templ)
|| DECL_TEMPLATE_TEMPLATE_PARM_P (templ))
{
bool entering_scope;
its name; we will look it up again during template instantiation. */
if (DECL_FUNCTION_TEMPLATE_P (decl) || !DECL_P (decl))
{
- tree scope = CP_DECL_CONTEXT (get_first_fn (decl));
+ tree scope = ovl_scope (decl);
if (TYPE_P (scope) && dependent_type_p (scope))
return identifier;
}
class-name
enum-name
typedef-name
+ simple-template-id [in c++0x]
enum-name:
identifier
/* If it's not a class-name, keep looking. */
if (!cp_parser_parse_definitely (parser))
{
- /* It must be a typedef-name or an enum-name. */
- return cp_parser_nonclass_name (parser);
+ if (cxx_dialect < cxx0x)
+ /* It must be a typedef-name or an enum-name. */
+ return cp_parser_nonclass_name (parser);
+
+ cp_parser_parse_tentatively (parser);
+ /* It is either a simple-template-id representing an
+ instantiation of an alias template... */
+ type_decl = cp_parser_template_id (parser,
+ /*template_keyword_p=*/false,
+ /*check_dependency_p=*/false,
+ /*is_declaration=*/false);
+ /* Note that this must be an instantiation of an alias template
+ because [temp.names]/6 says:
+
+ A template-id that names an alias template specialization
+ is a type-name.
+
+ Whereas [temp.names]/7 says:
+
+ A simple-template-id that names a class template
+ specialization is a class-name. */
+ if (type_decl != NULL_TREE
+ && TREE_CODE (type_decl) == TYPE_DECL
+ && TYPE_DECL_ALIAS_P (type_decl))
+ gcc_assert (DECL_TEMPLATE_INSTANTIATION (type_decl));
+ else
+ cp_parser_simulate_error (parser);
+
+ if (!cp_parser_parse_definitely (parser))
+ /* ... Or a typedef-name or an enum-name. */
+ return cp_parser_nonclass_name (parser);
}
return type_decl;
/* Look up the type-name. */
type_decl = cp_parser_lookup_name_simple (parser, identifier, token->location);
+ if (TREE_CODE (type_decl) == USING_DECL)
+ {
+ if (!DECL_DEPENDENT_P (type_decl))
+ type_decl = strip_using_decl (type_decl);
+ else if (USING_DECL_TYPENAME_P (type_decl))
+ {
+ /* We have found a type introduced by a using
+ declaration at class scope that refers to a dependent
+ type.
+
+ using typename :: [opt] nested-name-specifier unqualified-id ;
+ */
+ type_decl = make_typename_type (TREE_TYPE (type_decl),
+ DECL_NAME (type_decl),
+ typename_type, tf_error);
+ if (type_decl != error_mark_node)
+ type_decl = TYPE_NAME (type_decl);
+ }
+ }
+
if (TREE_CODE (type_decl) != TYPE_DECL
&& (objc_is_id (identifier) || objc_is_class_name (identifier)))
{
else if (tag_type == typename_type && TREE_CODE (decl) != TYPE_DECL)
type = NULL_TREE;
else
- type = TREE_TYPE (decl);
+ type = check_elaborated_type_specifier (tag_type, decl,
+ /*allow_template_p=*/true);
}
if (!type)
enum-specifier:
enum-head { enumerator-list [opt] }
+ enum-head { enumerator-list , } [C++0x]
enum-head:
enum-key identifier [opt] enum-base [opt]
GNU Extensions:
enum-key attributes[opt] identifier [opt] enum-base [opt]
{ enumerator-list [opt] }attributes[opt]
+ enum-key attributes[opt] identifier [opt] enum-base [opt]
+ { enumerator-list, }attributes[opt] [C++0x]
Returns an ENUM_TYPE representing the enumeration, or NULL_TREE
if the token stream isn't an enum-specifier after all. */
/* If the next token is a `}', there is a trailing comma. */
if (cp_lexer_next_token_is (parser->lexer, CPP_CLOSE_BRACE))
{
- if (!in_system_header)
- pedwarn (input_location, OPT_pedantic, "comma at end of enumerator list");
+ if (cxx_dialect < cxx0x && !in_system_header)
+ pedwarn (input_location, OPT_pedantic,
+ "comma at end of enumerator list");
break;
}
}
tree decl;
tree identifier;
tree qscope;
+ int oldcount = errorcount;
+ cp_token *diag_token = NULL;
if (access_declaration_p)
- cp_parser_parse_tentatively (parser);
+ {
+ diag_token = cp_lexer_peek_token (parser->lexer);
+ cp_parser_parse_tentatively (parser);
+ }
else
{
/* Look for the `using' keyword. */
/* Create the USING_DECL. */
decl = do_class_using_decl (parser->scope, identifier);
+ if (decl && typename_p)
+ USING_DECL_TYPENAME_P (decl) = 1;
+
if (check_for_bare_parameter_packs (decl))
return false;
- else
+ else
/* Add it to the list of members in this class. */
finish_member_declaration (decl);
}
/* Look for the final `;'. */
cp_parser_require (parser, CPP_SEMICOLON, RT_SEMICOLON);
-
+
+ if (access_declaration_p && errorcount == oldcount)
+ warning_at (diag_token->location, OPT_Wdeprecated,
+ "access declarations are deprecated "
+ "in favour of using-declarations; "
+ "suggestion: add the %<using%> keyword");
+
return true;
}
+/* Parse an alias-declaration.
+
+ alias-declaration:
+ using identifier attribute-specifier-seq [opt] = type-id */
+
+static tree
+cp_parser_alias_declaration (cp_parser* parser)
+{
+ tree id, type, decl, pushed_scope = NULL_TREE, attributes;
+ location_t id_location;
+ cp_declarator *declarator;
+ cp_decl_specifier_seq decl_specs;
+ bool member_p;
+ const char *saved_message = NULL;
+
+ /* Look for the `using' keyword. */
+ cp_parser_require_keyword (parser, RID_USING, RT_USING);
+ id_location = cp_lexer_peek_token (parser->lexer)->location;
+ id = cp_parser_identifier (parser);
+ if (id == error_mark_node)
+ return error_mark_node;
+
+ attributes = cp_parser_attributes_opt (parser);
+ if (attributes == error_mark_node)
+ return error_mark_node;
+
+ cp_parser_require (parser, CPP_EQ, RT_EQ);
+
+ /* Now we are going to parse the type-id of the declaration. */
+
+ /*
+ [dcl.type]/3 says:
+
+ "A type-specifier-seq shall not define a class or enumeration
+ unless it appears in the type-id of an alias-declaration (7.1.3) that
+ is not the declaration of a template-declaration."
+
+ In other words, if we currently are in an alias template, the
+ type-id should not define a type.
+
+ So let's set parser->type_definition_forbidden_message in that
+ case; cp_parser_check_type_definition (called by
+ cp_parser_class_specifier) will then emit an error if a type is
+ defined in the type-id. */
+ if (parser->num_template_parameter_lists)
+ {
+ saved_message = parser->type_definition_forbidden_message;
+ parser->type_definition_forbidden_message =
+ G_("types may not be defined in alias template declarations");
+ }
+
+ type = cp_parser_type_id (parser);
+
+ /* Restore the error message if need be. */
+ if (parser->num_template_parameter_lists)
+ parser->type_definition_forbidden_message = saved_message;
+
+ cp_parser_require (parser, CPP_SEMICOLON, RT_SEMICOLON);
+
+ if (cp_parser_error_occurred (parser))
+ return error_mark_node;
+
+ /* A typedef-name can also be introduced by an alias-declaration. The
+ identifier following the using keyword becomes a typedef-name. It has
+ the same semantics as if it were introduced by the typedef
+ specifier. In particular, it does not define a new type and it shall
+ not appear in the type-id. */
+
+ clear_decl_specs (&decl_specs);
+ decl_specs.type = type;
+ decl_specs.attributes = attributes;
+ ++decl_specs.specs[(int) ds_typedef];
+ ++decl_specs.specs[(int) ds_alias];
+
+ declarator = make_id_declarator (NULL_TREE, id, sfk_none);
+ declarator->id_loc = id_location;
+
+ member_p = at_class_scope_p ();
+ if (member_p)
+ decl = grokfield (declarator, &decl_specs, NULL_TREE, false,
+ NULL_TREE, attributes);
+ else
+ decl = start_decl (declarator, &decl_specs, 0,
+ attributes, NULL_TREE, &pushed_scope);
+ if (decl == error_mark_node)
+ return decl;
+
+ cp_finish_decl (decl, NULL_TREE, 0, NULL_TREE, 0);
+
+ if (pushed_scope)
+ pop_scope (pushed_scope);
+
+ /* If decl is a template, return its TEMPLATE_DECL so that it gets
+ added into the symbol table; otherwise, return the TYPE_DECL. */
+ if (DECL_LANG_SPECIFIC (decl)
+ && DECL_TEMPLATE_INFO (decl)
+ && PRIMARY_TEMPLATE_P (DECL_TI_TEMPLATE (decl)))
+ {
+ decl = DECL_TI_TEMPLATE (decl);
+ if (member_p)
+ check_member_template (decl);
+ }
+
+ return decl;
+}
+
/* Parse a using-directive.
using-directive:
function-definition:
__extension__ function-definition
+ TM Extension:
+
+ function-definition:
+ decl-specifier-seq [opt] declarator function-transaction-block
+
The DECL_SPECIFIERS apply to this declarator. Returns a
representation of the entity declared. If MEMBER_P is TRUE, then
this declarator appears in a class scope. The new DECL created by
{
/* We want to record the extra mangling scope for in-class
initializers of class members and initializers of static data
- member templates. The former is a C++0x feature which isn't
- implemented yet, and I expect it will involve deferring
+ member templates. The former involves deferring
parsing of the initializer until end of class as with default
arguments. So right here we only handle the latter. */
if (!member_p && processing_template_decl)
&non_constant_p);
if (!non_constant_p)
/* OK */;
- /* Normally, the array bound must be an integral constant
- expression. However, as an extension, we allow VLAs
- in function scopes as long as they aren't part of a
- parameter declaration. */
+ else if (error_operand_p (bounds))
+ /* Already gave an error. */;
else if (!parser->in_function_body
|| current_binding_level->kind == sk_function_parms)
{
+ /* Normally, the array bound must be an integral constant
+ expression. However, as an extension, we allow VLAs
+ in function scopes as long as they aren't part of a
+ parameter declaration. */
cp_parser_error (parser,
"array bound is not an integer constant");
bounds = error_mark_node;
}
- else if (processing_template_decl && !error_operand_p (bounds))
+ else if (processing_template_decl)
{
/* Remember this wasn't a constant-expression. */
bounds = build_nop (TREE_TYPE (bounds), bounds);
if (TREE_CODE (parser->scope) == NAMESPACE_DECL)
error_at (token->location, "%qD is a namespace", parser->scope);
+ else if (TREE_CODE (parser->scope) == ENUMERAL_TYPE)
+ error_at (token->location, "cannot form pointer to member of "
+ "non-class %q#T", parser->scope);
else
{
/* The type of which the member is a member is given by the
/* If the next token is `=', then process a default argument. */
if (cp_lexer_next_token_is (parser->lexer, CPP_EQ))
{
+ token = cp_lexer_peek_token (parser->lexer);
/* If we are defining a class, then the tokens that make up the
default argument must be saved and processed later. */
if (!template_parm_p && at_class_scope_p ()
&& TYPE_BEING_DEFINED (current_class_type)
&& !LAMBDA_TYPE_P (current_class_type))
- {
- unsigned depth = 0;
- int maybe_template_id = 0;
- cp_token *first_token;
- cp_token *token;
-
- /* Add tokens until we have processed the entire default
- argument. We add the range [first_token, token). */
- first_token = cp_lexer_peek_token (parser->lexer);
- while (true)
- {
- bool done = false;
-
- /* Peek at the next token. */
- token = cp_lexer_peek_token (parser->lexer);
- /* What we do depends on what token we have. */
- switch (token->type)
- {
- /* In valid code, a default argument must be
- immediately followed by a `,' `)', or `...'. */
- case CPP_COMMA:
- if (depth == 0 && maybe_template_id)
- {
- /* If we've seen a '<', we might be in a
- template-argument-list. Until Core issue 325 is
- resolved, we don't know how this situation ought
- to be handled, so try to DTRT. We check whether
- what comes after the comma is a valid parameter
- declaration list. If it is, then the comma ends
- the default argument; otherwise the default
- argument continues. */
- bool error = false;
- tree t;
-
- /* Set ITALP so cp_parser_parameter_declaration_list
- doesn't decide to commit to this parse. */
- bool saved_italp = parser->in_template_argument_list_p;
- parser->in_template_argument_list_p = true;
-
- cp_parser_parse_tentatively (parser);
- cp_lexer_consume_token (parser->lexer);
- begin_scope (sk_function_parms, NULL_TREE);
- cp_parser_parameter_declaration_list (parser, &error);
- for (t = current_binding_level->names; t; t = DECL_CHAIN (t))
- pop_binding (DECL_NAME (t), t);
- leave_scope ();
- if (!cp_parser_error_occurred (parser) && !error)
- done = true;
- cp_parser_abort_tentative_parse (parser);
-
- parser->in_template_argument_list_p = saved_italp;
- break;
- }
- case CPP_CLOSE_PAREN:
- case CPP_ELLIPSIS:
- /* If we run into a non-nested `;', `}', or `]',
- then the code is invalid -- but the default
- argument is certainly over. */
- case CPP_SEMICOLON:
- case CPP_CLOSE_BRACE:
- case CPP_CLOSE_SQUARE:
- if (depth == 0)
- done = true;
- /* Update DEPTH, if necessary. */
- else if (token->type == CPP_CLOSE_PAREN
- || token->type == CPP_CLOSE_BRACE
- || token->type == CPP_CLOSE_SQUARE)
- --depth;
- break;
-
- case CPP_OPEN_PAREN:
- case CPP_OPEN_SQUARE:
- case CPP_OPEN_BRACE:
- ++depth;
- break;
-
- case CPP_LESS:
- if (depth == 0)
- /* This might be the comparison operator, or it might
- start a template argument list. */
- ++maybe_template_id;
- break;
-
- case CPP_RSHIFT:
- if (cxx_dialect == cxx98)
- break;
- /* Fall through for C++0x, which treats the `>>'
- operator like two `>' tokens in certain
- cases. */
-
- case CPP_GREATER:
- if (depth == 0)
- {
- /* This might be an operator, or it might close a
- template argument list. But if a previous '<'
- started a template argument list, this will have
- closed it, so we can't be in one anymore. */
- maybe_template_id -= 1 + (token->type == CPP_RSHIFT);
- if (maybe_template_id < 0)
- maybe_template_id = 0;
- }
- break;
-
- /* If we run out of tokens, issue an error message. */
- case CPP_EOF:
- case CPP_PRAGMA_EOL:
- error_at (token->location, "file ends in default argument");
- done = true;
- break;
-
- case CPP_NAME:
- case CPP_SCOPE:
- /* In these cases, we should look for template-ids.
- For example, if the default argument is
- `X<int, double>()', we need to do name lookup to
- figure out whether or not `X' is a template; if
- so, the `,' does not end the default argument.
-
- That is not yet done. */
- break;
-
- default:
- break;
- }
-
- /* If we've reached the end, stop. */
- if (done)
- break;
-
- /* Add the token to the token block. */
- token = cp_lexer_consume_token (parser->lexer);
- }
-
- /* Create a DEFAULT_ARG to represent the unparsed default
- argument. */
- default_argument = make_node (DEFAULT_ARG);
- DEFARG_TOKENS (default_argument)
- = cp_token_cache_new (first_token, token);
- DEFARG_INSTANTIATIONS (default_argument) = NULL;
- }
+ default_argument = cp_parser_cache_defarg (parser, /*nsdmi=*/false);
/* Outside of a class definition, we can just parse the
assignment-expression. */
else
- {
- token = cp_lexer_peek_token (parser->lexer);
- default_argument
- = cp_parser_default_argument (parser, template_parm_p);
- }
+ default_argument
+ = cp_parser_default_argument (parser, template_parm_p);
if (!parser->default_arg_ok_p)
{
cp_parser_function_body changed its state. */
if (check_body_p)
{
- list = body;
- if (TREE_CODE (list) == BIND_EXPR)
- list = BIND_EXPR_BODY (list);
- if (TREE_CODE (list) == STATEMENT_LIST
- && STATEMENT_LIST_TAIL (list) != NULL)
+ list = cur_stmt_list;
+ if (STATEMENT_LIST_TAIL (list))
last = STATEMENT_LIST_TAIL (list)->stmt;
}
/* Parse the function-body. */
&& !c_dialect_objc ()
&& cp_lexer_next_token_is (parser->lexer, CPP_OPEN_SQUARE))
{
+ /* In C++11, [ could start a lambda-introducer. */
+ cp_parser_parse_tentatively (parser);
cp_lexer_consume_token (parser->lexer);
designator = cp_parser_constant_expression (parser, false, NULL);
cp_parser_require (parser, CPP_CLOSE_SQUARE, RT_CLOSE_SQUARE);
cp_parser_require (parser, CPP_EQ, RT_EQ);
+ if (!cp_parser_parse_definitely (parser))
+ designator = NULL_TREE;
}
else
designator = NULL_TREE;
decl = TYPE_NAME (decl);
}
+ decl = strip_using_decl (decl);
+
/* Check to see that it is really the name of a class. */
if (TREE_CODE (decl) == TEMPLATE_ID_EXPR
&& TREE_CODE (TREE_OPERAND (decl, 0)) == IDENTIFIER_NODE
:: [opt] nested-name-specifier template [opt] unqualified-id ;
using-declaration
template-declaration
+ alias-declaration
member-declarator-list:
member-declarator
/* Check for a using-declaration. */
if (cp_lexer_next_token_is_keyword (parser->lexer, RID_USING))
{
- /* Parse the using-declaration. */
- cp_parser_using_declaration (parser,
- /*access_declaration_p=*/false);
- return;
+ if (cxx_dialect < cxx0x)
+ {
+ /* Parse the using-declaration. */
+ cp_parser_using_declaration (parser,
+ /*access_declaration_p=*/false);
+ return;
+ }
+ else
+ {
+ tree decl;
+ cp_parser_parse_tentatively (parser);
+ decl = cp_parser_alias_declaration (parser);
+ if (cp_parser_parse_definitely (parser))
+ finish_member_declaration (decl);
+ else
+ cp_parser_using_declaration (parser,
+ /*access_declaration_p=*/false);
+ return;
+ }
}
/* Check for @defs. */
parser->colon_corrects_to_scope_p = false;
if (cp_parser_using_declaration (parser, /*access_declaration=*/true))
- goto out;
+ goto out;
/* Parse the decl-specifier-seq. */
decl_spec_token_start = cp_lexer_peek_token (parser->lexer);
possible that this fact is an oversight in the
standard, since a pure function may be defined
outside of the class-specifier. */
- if (initializer)
+ if (initializer && initializer_token_start)
error_at (initializer_token_start->location,
"pure-specifier on function-definition");
decl = cp_parser_save_member_function_body (parser,
/* Exception handling [gram.exception] */
-/* Parse an (optional) exception-specification.
+/* Parse an (optional) noexcept-specification.
- exception-specification:
- throw ( type-id-list [opt] )
+ noexcept-specification:
+ noexcept ( constant-expression ) [opt]
- Returns a TREE_LIST representing the exception-specification. The
- TREE_VALUE of each node is a type. */
+ If no noexcept-specification is present, returns NULL_TREE.
+ Otherwise, if REQUIRE_CONSTEXPR is false, then either parse and return any
+ expression if parentheses follow noexcept, or return BOOLEAN_TRUE_NODE if
+ there are no parentheses. CONSUMED_EXPR will be set accordingly.
+ Otherwise, returns a noexcept specification unless RETURN_COND is true,
+ in which case a boolean condition is returned instead. */
static tree
-cp_parser_exception_specification_opt (cp_parser* parser)
+cp_parser_noexcept_specification_opt (cp_parser* parser,
+ bool require_constexpr,
+ bool* consumed_expr,
+ bool return_cond)
{
cp_token *token;
- tree type_id_list;
const char *saved_message;
/* Peek at the next token. */
{
cp_lexer_consume_token (parser->lexer);
- /* Types may not be defined in an exception-specification. */
- saved_message = parser->type_definition_forbidden_message;
- parser->type_definition_forbidden_message
- = G_("types may not be defined in an exception-specification");
+ if (require_constexpr)
+ {
+ /* Types may not be defined in an exception-specification. */
+ saved_message = parser->type_definition_forbidden_message;
+ parser->type_definition_forbidden_message
+ = G_("types may not be defined in an exception-specification");
- expr = cp_parser_constant_expression (parser, false, NULL);
+ expr = cp_parser_constant_expression (parser, false, NULL);
- /* Restore the saved message. */
- parser->type_definition_forbidden_message = saved_message;
+ /* Restore the saved message. */
+ parser->type_definition_forbidden_message = saved_message;
+ }
+ else
+ {
+ expr = cp_parser_expression (parser, false, NULL);
+ *consumed_expr = true;
+ }
cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN);
}
else
- expr = boolean_true_node;
+ {
+ expr = boolean_true_node;
+ if (!require_constexpr)
+ *consumed_expr = false;
+ }
- return build_noexcept_spec (expr, tf_warning_or_error);
+ /* We cannot build a noexcept-spec right away because this will check
+ that expr is a constexpr. */
+ if (!return_cond)
+ return build_noexcept_spec (expr, tf_warning_or_error);
+ else
+ return expr;
}
+ else
+ return NULL_TREE;
+}
+
+/* Parse an (optional) exception-specification.
+
+ exception-specification:
+ throw ( type-id-list [opt] )
+
+ Returns a TREE_LIST representing the exception-specification. The
+ TREE_VALUE of each node is a type. */
+
+static tree
+cp_parser_exception_specification_opt (cp_parser* parser)
+{
+ cp_token *token;
+ tree type_id_list;
+ const char *saved_message;
+
+ /* Peek at the next token. */
+ token = cp_lexer_peek_token (parser->lexer);
+
+ /* Is it a noexcept-specification? */
+ type_id_list = cp_parser_noexcept_specification_opt(parser, true, NULL,
+ false);
+ if (type_id_list != NULL_TREE)
+ return type_id_list;
/* If it's not `throw', then there's no exception-specification. */
if (!cp_parser_is_keyword (token, RID_THROW))
object_decl = lookup_member (object_type,
name,
/*protect=*/0,
- tag_type != none_type);
+ tag_type != none_type,
+ tf_warning_or_error);
/* Look it up in the enclosing context, too. */
decl = lookup_name_real (name, tag_type != none_type,
/*nonclass=*/0,
start_lambda_scope (current_function_decl);
- /* If the next token is `try', then we are looking at a
- function-try-block. */
- if (cp_lexer_next_token_is_keyword (parser->lexer, RID_TRY))
+ /* If the next token is `try', `__transaction_atomic', or
+ `__transaction_relaxed`, then we are looking at either function-try-block
+ or function-transaction-block. Note that all of these include the
+ function-body. */
+ if (cp_lexer_next_token_is_keyword (parser->lexer, RID_TRANSACTION_ATOMIC))
+ ctor_initializer_p = cp_parser_function_transaction (parser,
+ RID_TRANSACTION_ATOMIC);
+ else if (cp_lexer_next_token_is_keyword (parser->lexer,
+ RID_TRANSACTION_RELAXED))
+ ctor_initializer_p = cp_parser_function_transaction (parser,
+ RID_TRANSACTION_RELAXED);
+ else if (cp_lexer_next_token_is_keyword (parser->lexer, RID_TRY))
ctor_initializer_p = cp_parser_function_try_block (parser);
- /* A function-try-block includes the function-body, so we only do
- this next part if we're not processing a function-try-block. */
else
ctor_initializer_p
= cp_parser_ctor_initializer_opt_and_function_body (parser);
if (cp_lexer_next_token_is_keyword (parser->lexer,
RID_TEMPLATE))
cp_parser_template_declaration_after_export (parser, member_p);
+ else if (cxx_dialect >= cxx0x
+ && cp_lexer_next_token_is_keyword (parser->lexer, RID_USING))
+ decl = cp_parser_alias_declaration (parser);
else
{
/* There are no access checks when parsing a template, as we do not
static tree
cp_parser_save_nsdmi (cp_parser* parser)
{
- /* Save away the tokens that make up the body of the
- function. */
- cp_token *first = parser->lexer->next_token;
- cp_token *last;
- tree node;
-
- /* Save tokens until the next comma or semicolon. */
- cp_parser_cache_group (parser, CPP_COMMA, /*depth=*/0);
-
- last = parser->lexer->next_token;
-
- node = make_node (DEFAULT_ARG);
- DEFARG_TOKENS (node) = cp_token_cache_new (first, last);
- DEFARG_INSTANTIATIONS (node) = NULL;
-
- return node;
+ return cp_parser_cache_defarg (parser, /*nsdmi=*/true);
}
-
/* Parse a template-argument-list, as well as the trailing ">" (but
not the opening "<"). See cp_parser_template_argument_list for the
return value. */
tree parsed_arg;
bool dummy;
+ if (default_arg == error_mark_node)
+ return error_mark_node;
+
/* Push the saved tokens for the default argument onto the parser's
lexer stack. */
tokens = DEFARG_TOKENS (default_arg);
case RT_AT_THROW:
cp_parser_error (parser, "expected %<@throw%>");
return;
+ case RT_TRANSACTION_ATOMIC:
+ cp_parser_error (parser, "expected %<__transaction_atomic%>");
+ return;
+ case RT_TRANSACTION_RELAXED:
+ cp_parser_error (parser, "expected %<__transaction_relaxed%>");
+ return;
default:
break;
}
|| token->type == CPP_COLON
/* A function-try-block begins with `try'. */
|| token->keyword == RID_TRY
+ /* A function-transaction-block begins with `__transaction_atomic'
+ or `__transaction_relaxed'. */
+ || token->keyword == RID_TRANSACTION_ATOMIC
+ || token->keyword == RID_TRANSACTION_RELAXED
/* The named return value extension begins with `return'. */
|| token->keyword == RID_RETURN);
}
static void
cp_parser_check_class_key (enum tag_types class_key, tree type)
{
+ if (type == error_mark_node)
+ return;
if ((TREE_CODE (type) == UNION_TYPE) != (class_key == union_type))
- permerror (input_location, "%qs tag used in naming %q#T",
- class_key == union_type ? "union"
- : class_key == record_type ? "struct" : "class",
- type);
+ {
+ permerror (input_location, "%qs tag used in naming %q#T",
+ class_key == union_type ? "union"
+ : class_key == record_type ? "struct" : "class",
+ type);
+ inform (DECL_SOURCE_LOCATION (TYPE_NAME (type)),
+ "%q#T was previously declared here", type);
+ }
}
/* Issue an error message if DECL is redeclared with different
kind of syntax error. */
return true;
- /* If we're caching something finished by a comma (or semicolon),
- such as an NSDMI, don't consume the comma. */
- if (end == CPP_COMMA
- && (token->type == CPP_SEMICOLON || token->type == CPP_COMMA))
- return false;
-
/* Consume the token. */
cp_lexer_consume_token (parser->lexer);
/* See if it starts a new group. */
}
}
+/* Like above, for caching a default argument or NSDMI. Both of these are
+ terminated by a non-nested comma, but it can be unclear whether or not a
+ comma is nested in a template argument list unless we do more parsing.
+ In order to handle this ambiguity, when we encounter a ',' after a '<'
+ we try to parse what follows as a parameter-declaration-list (in the
+ case of a default argument) or a member-declarator (in the case of an
+ NSDMI). If that succeeds, then we stop caching. */
+
+static tree
+cp_parser_cache_defarg (cp_parser *parser, bool nsdmi)
+{
+ unsigned depth = 0;
+ int maybe_template_id = 0;
+ cp_token *first_token;
+ cp_token *token;
+ tree default_argument;
+
+ /* Add tokens until we have processed the entire default
+ argument. We add the range [first_token, token). */
+ first_token = cp_lexer_peek_token (parser->lexer);
+ if (first_token->type == CPP_OPEN_BRACE)
+ {
+ /* For list-initialization, this is straightforward. */
+ cp_parser_cache_group (parser, CPP_CLOSE_BRACE, /*depth=*/0);
+ token = cp_lexer_peek_token (parser->lexer);
+ }
+ else while (true)
+ {
+ bool done = false;
+
+ /* Peek at the next token. */
+ token = cp_lexer_peek_token (parser->lexer);
+ /* What we do depends on what token we have. */
+ switch (token->type)
+ {
+ /* In valid code, a default argument must be
+ immediately followed by a `,' `)', or `...'. */
+ case CPP_COMMA:
+ if (depth == 0 && maybe_template_id)
+ {
+ /* If we've seen a '<', we might be in a
+ template-argument-list. Until Core issue 325 is
+ resolved, we don't know how this situation ought
+ to be handled, so try to DTRT. We check whether
+ what comes after the comma is a valid parameter
+ declaration list. If it is, then the comma ends
+ the default argument; otherwise the default
+ argument continues. */
+ bool error = false;
+ tree t;
+
+ /* Set ITALP so cp_parser_parameter_declaration_list
+ doesn't decide to commit to this parse. */
+ bool saved_italp = parser->in_template_argument_list_p;
+ parser->in_template_argument_list_p = true;
+
+ cp_parser_parse_tentatively (parser);
+ cp_lexer_consume_token (parser->lexer);
+
+ if (nsdmi)
+ {
+ int ctor_dtor_or_conv_p;
+ cp_parser_declarator (parser, CP_PARSER_DECLARATOR_NAMED,
+ &ctor_dtor_or_conv_p,
+ /*parenthesized_p=*/NULL,
+ /*member_p=*/true);
+ }
+ else
+ {
+ begin_scope (sk_function_parms, NULL_TREE);
+ cp_parser_parameter_declaration_list (parser, &error);
+ for (t = current_binding_level->names; t; t = DECL_CHAIN (t))
+ pop_binding (DECL_NAME (t), t);
+ leave_scope ();
+ }
+ if (!cp_parser_error_occurred (parser) && !error)
+ done = true;
+ cp_parser_abort_tentative_parse (parser);
+
+ parser->in_template_argument_list_p = saved_italp;
+ break;
+ }
+ case CPP_CLOSE_PAREN:
+ case CPP_ELLIPSIS:
+ /* If we run into a non-nested `;', `}', or `]',
+ then the code is invalid -- but the default
+ argument is certainly over. */
+ case CPP_SEMICOLON:
+ case CPP_CLOSE_BRACE:
+ case CPP_CLOSE_SQUARE:
+ if (depth == 0)
+ done = true;
+ /* Update DEPTH, if necessary. */
+ else if (token->type == CPP_CLOSE_PAREN
+ || token->type == CPP_CLOSE_BRACE
+ || token->type == CPP_CLOSE_SQUARE)
+ --depth;
+ break;
+
+ case CPP_OPEN_PAREN:
+ case CPP_OPEN_SQUARE:
+ case CPP_OPEN_BRACE:
+ ++depth;
+ break;
+
+ case CPP_LESS:
+ if (depth == 0)
+ /* This might be the comparison operator, or it might
+ start a template argument list. */
+ ++maybe_template_id;
+ break;
+
+ case CPP_RSHIFT:
+ if (cxx_dialect == cxx98)
+ break;
+ /* Fall through for C++0x, which treats the `>>'
+ operator like two `>' tokens in certain
+ cases. */
+
+ case CPP_GREATER:
+ if (depth == 0)
+ {
+ /* This might be an operator, or it might close a
+ template argument list. But if a previous '<'
+ started a template argument list, this will have
+ closed it, so we can't be in one anymore. */
+ maybe_template_id -= 1 + (token->type == CPP_RSHIFT);
+ if (maybe_template_id < 0)
+ maybe_template_id = 0;
+ }
+ break;
+
+ /* If we run out of tokens, issue an error message. */
+ case CPP_EOF:
+ case CPP_PRAGMA_EOL:
+ error_at (token->location, "file ends in default argument");
+ done = true;
+ break;
+
+ case CPP_NAME:
+ case CPP_SCOPE:
+ /* In these cases, we should look for template-ids.
+ For example, if the default argument is
+ `X<int, double>()', we need to do name lookup to
+ figure out whether or not `X' is a template; if
+ so, the `,' does not end the default argument.
+
+ That is not yet done. */
+ break;
+
+ default:
+ break;
+ }
+
+ /* If we've reached the end, stop. */
+ if (done)
+ break;
+
+ /* Add the token to the token block. */
+ token = cp_lexer_consume_token (parser->lexer);
+ }
+
+ /* Create a DEFAULT_ARG to represent the unparsed default
+ argument. */
+ default_argument = make_node (DEFAULT_ARG);
+ DEFARG_TOKENS (default_argument)
+ = cp_token_cache_new (first_token, token);
+ DEFARG_INSTANTIATIONS (default_argument) = NULL;
+
+ return default_argument;
+}
+
/* Begin parsing tentatively. We always save tokens while parsing
tentatively so that if the tentative parsing fails we can restore the
tokens. */
{
/* If decl is an iterator, preserve the operator on decl
until finish_omp_for. */
- if (decl
- && ((type_dependent_expression_p (decl)
- && !POINTER_TYPE_P (TREE_TYPE (decl)))
- || CLASS_TYPE_P (TREE_TYPE (decl))))
- incr = cp_parser_omp_for_incr (parser, decl);
+ if (real_decl
+ && ((processing_template_decl
+ && !POINTER_TYPE_P (TREE_TYPE (real_decl)))
+ || CLASS_TYPE_P (TREE_TYPE (real_decl))))
+ incr = cp_parser_omp_for_incr (parser, real_decl);
else
incr = cp_parser_expression (parser, false, NULL);
}
SET_EXPR_LOCATION (stmt, pragma_tok->location);
}
\f
+/* Transactional Memory parsing routines. */
+
+/* Parse a transaction attribute.
+
+ txn-attribute:
+ attribute
+ [ [ identifier ] ]
+
+ ??? Simplify this when C++0x bracket attributes are
+ implemented properly. */
+
+static tree
+cp_parser_txn_attribute_opt (cp_parser *parser)
+{
+ cp_token *token;
+ tree attr_name, attr = NULL;
+
+ if (cp_lexer_next_token_is_keyword (parser->lexer, RID_ATTRIBUTE))
+ return cp_parser_attributes_opt (parser);
+
+ if (cp_lexer_next_token_is_not (parser->lexer, CPP_OPEN_SQUARE))
+ return NULL_TREE;
+ cp_lexer_consume_token (parser->lexer);
+ if (!cp_parser_require (parser, CPP_OPEN_SQUARE, RT_OPEN_SQUARE))
+ goto error1;
+
+ token = cp_lexer_peek_token (parser->lexer);
+ if (token->type == CPP_NAME || token->type == CPP_KEYWORD)
+ {
+ token = cp_lexer_consume_token (parser->lexer);
+
+ attr_name = (token->type == CPP_KEYWORD
+ /* For keywords, use the canonical spelling,
+ not the parsed identifier. */
+ ? ridpointers[(int) token->keyword]
+ : token->u.value);
+ attr = build_tree_list (attr_name, NULL_TREE);
+ }
+ else
+ cp_parser_error (parser, "expected identifier");
+
+ cp_parser_require (parser, CPP_CLOSE_SQUARE, RT_CLOSE_SQUARE);
+ error1:
+ cp_parser_require (parser, CPP_CLOSE_SQUARE, RT_CLOSE_SQUARE);
+ return attr;
+}
+
+/* Parse a __transaction_atomic or __transaction_relaxed statement.
+
+ transaction-statement:
+ __transaction_atomic txn-attribute[opt] txn-noexcept-spec[opt]
+ compound-statement
+ __transaction_relaxed txn-noexcept-spec[opt] compound-statement
+*/
+
+static tree
+cp_parser_transaction (cp_parser *parser, enum rid keyword)
+{
+ unsigned char old_in = parser->in_transaction;
+ unsigned char this_in = 1, new_in;
+ cp_token *token;
+ tree stmt, attrs, noex;
+
+ gcc_assert (keyword == RID_TRANSACTION_ATOMIC
+ || keyword == RID_TRANSACTION_RELAXED);
+ token = cp_parser_require_keyword (parser, keyword,
+ (keyword == RID_TRANSACTION_ATOMIC ? RT_TRANSACTION_ATOMIC
+ : RT_TRANSACTION_RELAXED));
+ gcc_assert (token != NULL);
+
+ if (keyword == RID_TRANSACTION_RELAXED)
+ this_in |= TM_STMT_ATTR_RELAXED;
+ else
+ {
+ attrs = cp_parser_txn_attribute_opt (parser);
+ if (attrs)
+ this_in |= parse_tm_stmt_attr (attrs, TM_STMT_ATTR_OUTER);
+ }
+
+ /* Parse a noexcept specification. */
+ noex = cp_parser_noexcept_specification_opt (parser, true, NULL, true);
+
+ /* Keep track if we're in the lexical scope of an outer transaction. */
+ new_in = this_in | (old_in & TM_STMT_ATTR_OUTER);
+
+ stmt = begin_transaction_stmt (token->location, NULL, this_in);
+
+ parser->in_transaction = new_in;
+ cp_parser_compound_statement (parser, NULL, false, false);
+ parser->in_transaction = old_in;
+
+ finish_transaction_stmt (stmt, NULL, this_in, noex);
+
+ return stmt;
+}
+
+/* Parse a __transaction_atomic or __transaction_relaxed expression.
+
+ transaction-expression:
+ __transaction_atomic txn-noexcept-spec[opt] ( expression )
+ __transaction_relaxed txn-noexcept-spec[opt] ( expression )
+*/
+
+static tree
+cp_parser_transaction_expression (cp_parser *parser, enum rid keyword)
+{
+ unsigned char old_in = parser->in_transaction;
+ unsigned char this_in = 1;
+ cp_token *token;
+ tree expr, noex;
+ bool noex_expr;
+
+ gcc_assert (keyword == RID_TRANSACTION_ATOMIC
+ || keyword == RID_TRANSACTION_RELAXED);
+
+ if (!flag_tm)
+ error (keyword == RID_TRANSACTION_RELAXED
+ ? G_("%<__transaction_relaxed%> without transactional memory "
+ "support enabled")
+ : G_("%<__transaction_atomic%> without transactional memory "
+ "support enabled"));
+
+ token = cp_parser_require_keyword (parser, keyword,
+ (keyword == RID_TRANSACTION_ATOMIC ? RT_TRANSACTION_ATOMIC
+ : RT_TRANSACTION_RELAXED));
+ gcc_assert (token != NULL);
+
+ if (keyword == RID_TRANSACTION_RELAXED)
+ this_in |= TM_STMT_ATTR_RELAXED;
+
+ /* Set this early. This might mean that we allow transaction_cancel in
+ an expression that we find out later actually has to be a constexpr.
+ However, we expect that cxx_constant_value will be able to deal with
+ this; also, if the noexcept has no constexpr, then what we parse next
+ really is a transaction's body. */
+ parser->in_transaction = this_in;
+
+ /* Parse a noexcept specification. */
+ noex = cp_parser_noexcept_specification_opt (parser, false, &noex_expr,
+ true);
+
+ if (!noex || !noex_expr
+ || cp_lexer_peek_token (parser->lexer)->type == CPP_OPEN_PAREN)
+ {
+ cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN);
+
+ expr = cp_parser_expression (parser, /*cast_p=*/false, NULL);
+ finish_parenthesized_expr (expr);
+
+ cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN);
+ }
+ else
+ {
+ /* The only expression that is available got parsed for the noexcept
+ already. noexcept is true then. */
+ expr = noex;
+ noex = boolean_true_node;
+ }
+
+ expr = build_transaction_expr (token->location, expr, this_in, noex);
+ parser->in_transaction = old_in;
+
+ if (cp_parser_non_integral_constant_expression (parser, NIC_TRANSACTION))
+ return error_mark_node;
+
+ return (flag_tm ? expr : error_mark_node);
+}
+
+/* Parse a function-transaction-block.
+
+ function-transaction-block:
+ __transaction_atomic txn-attribute[opt] ctor-initializer[opt]
+ function-body
+ __transaction_atomic txn-attribute[opt] function-try-block
+ __transaction_relaxed ctor-initializer[opt] function-body
+ __transaction_relaxed function-try-block
+*/
+
+static bool
+cp_parser_function_transaction (cp_parser *parser, enum rid keyword)
+{
+ unsigned char old_in = parser->in_transaction;
+ unsigned char new_in = 1;
+ tree compound_stmt, stmt, attrs;
+ bool ctor_initializer_p;
+ cp_token *token;
+
+ gcc_assert (keyword == RID_TRANSACTION_ATOMIC
+ || keyword == RID_TRANSACTION_RELAXED);
+ token = cp_parser_require_keyword (parser, keyword,
+ (keyword == RID_TRANSACTION_ATOMIC ? RT_TRANSACTION_ATOMIC
+ : RT_TRANSACTION_RELAXED));
+ gcc_assert (token != NULL);
+
+ if (keyword == RID_TRANSACTION_RELAXED)
+ new_in |= TM_STMT_ATTR_RELAXED;
+ else
+ {
+ attrs = cp_parser_txn_attribute_opt (parser);
+ if (attrs)
+ new_in |= parse_tm_stmt_attr (attrs, TM_STMT_ATTR_OUTER);
+ }
+
+ stmt = begin_transaction_stmt (token->location, &compound_stmt, new_in);
+
+ parser->in_transaction = new_in;
+
+ if (cp_lexer_next_token_is_keyword (parser->lexer, RID_TRY))
+ ctor_initializer_p = cp_parser_function_try_block (parser);
+ else
+ ctor_initializer_p
+ = cp_parser_ctor_initializer_opt_and_function_body (parser);
+
+ parser->in_transaction = old_in;
+
+ finish_transaction_stmt (stmt, compound_stmt, new_in, NULL_TREE);
+
+ return ctor_initializer_p;
+}
+
+/* Parse a __transaction_cancel statement.
+
+ cancel-statement:
+ __transaction_cancel txn-attribute[opt] ;
+ __transaction_cancel txn-attribute[opt] throw-expression ;
+
+ ??? Cancel and throw is not yet implemented. */
+
+static tree
+cp_parser_transaction_cancel (cp_parser *parser)
+{
+ cp_token *token;
+ bool is_outer = false;
+ tree stmt, attrs;
+
+ token = cp_parser_require_keyword (parser, RID_TRANSACTION_CANCEL,
+ RT_TRANSACTION_CANCEL);
+ gcc_assert (token != NULL);
+
+ attrs = cp_parser_txn_attribute_opt (parser);
+ if (attrs)
+ is_outer = (parse_tm_stmt_attr (attrs, TM_STMT_ATTR_OUTER) != 0);
+
+ /* ??? Parse cancel-and-throw here. */
+
+ cp_parser_require (parser, CPP_SEMICOLON, RT_SEMICOLON);
+
+ if (!flag_tm)
+ {
+ error_at (token->location, "%<__transaction_cancel%> without "
+ "transactional memory support enabled");
+ return error_mark_node;
+ }
+ else if (parser->in_transaction & TM_STMT_ATTR_RELAXED)
+ {
+ error_at (token->location, "%<__transaction_cancel%> within a "
+ "%<__transaction_relaxed%>");
+ return error_mark_node;
+ }
+ else if (is_outer)
+ {
+ if ((parser->in_transaction & TM_STMT_ATTR_OUTER) == 0
+ && !is_tm_may_cancel_outer (current_function_decl))
+ {
+ error_at (token->location, "outer %<__transaction_cancel%> not "
+ "within outer %<__transaction_atomic%>");
+ error_at (token->location,
+ " or a %<transaction_may_cancel_outer%> function");
+ return error_mark_node;
+ }
+ }
+ else if (parser->in_transaction == 0)
+ {
+ error_at (token->location, "%<__transaction_cancel%> not within "
+ "%<__transaction_atomic%>");
+ return error_mark_node;
+ }
+
+ stmt = build_tm_abort_call (token->location, is_outer);
+ add_stmt (stmt);
+ finish_stmt ();
+
+ return stmt;
+}
+\f
/* The parser. */
static GTY (()) cp_parser *the_parser;