/* C++ Parser.
Copyright (C) 2000, 2001, 2002, 2003, 2004,
- 2005, 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
+ 2005, 2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc.
Written by Mark Mitchell <mark@codesourcery.com>.
This file is part of GCC.
#include "system.h"
#include "coretypes.h"
#include "tm.h"
+#include "timevar.h"
#include "cpplib.h"
#include "tree.h"
#include "cp-tree.h"
case RID_TYPEOF:
/* C++0x extensions. */
case RID_DECLTYPE:
+ case RID_UNDERLYING_TYPE:
return true;
default:
VAR_DECLs or FUNCTION_DECLs) should do that directly. */
static cp_declarator *make_call_declarator
- (cp_declarator *, tree, cp_cv_quals, tree, tree);
+ (cp_declarator *, tree, cp_cv_quals, cp_virt_specifiers, tree, tree);
static cp_declarator *make_array_declarator
(cp_declarator *, tree);
static cp_declarator *make_pointer_declarator
make_call_declarator (cp_declarator *target,
tree parms,
cp_cv_quals cv_qualifiers,
+ cp_virt_specifiers virt_specifiers,
tree exception_specification,
tree late_return_type)
{
declarator->declarator = target;
declarator->u.function.parameters = parms;
declarator->u.function.qualifiers = cv_qualifiers;
+ declarator->u.function.virt_specifiers = virt_specifiers;
declarator->u.function.exception_specification = exception_specification;
declarator->u.function.late_return_type = late_return_type;
if (target)
(cp_parser *, tree, tree);
static tree cp_parser_range_for
(cp_parser *, tree, tree, tree);
+static tree cp_parser_perform_range_for_lookup
+ (tree, tree *, tree *);
+static tree cp_parser_range_for_member_function
+ (tree, tree);
static tree cp_parser_jump_statement
(cp_parser *);
static void cp_parser_declaration_statement
(cp_parser *, tree *, cp_cv_quals *);
static cp_cv_quals cp_parser_cv_qualifier_seq_opt
(cp_parser *);
+static cp_virt_specifiers cp_parser_virt_specifier_seq_opt
+ (cp_parser *);
static tree cp_parser_late_return_type_opt
(cp_parser *);
static tree cp_parser_declarator_id
location_t location)
{
tree decl, old_scope;
+ cp_parser_commit_to_tentative_parse (parser);
/* Try to lookup the identifier. */
old_scope = parser->scope;
parser->scope = scope;
else
gcc_unreachable ();
}
- cp_parser_commit_to_tentative_parse (parser);
}
/* Check for a common situation where a type-name should be present,
`&A::B' might be a pointer-to-member, but `&(A::B)' is
not. */
finish_parenthesized_expr (expr);
+ /* DR 705: Wrapping an unqualified name in parentheses
+ suppresses arg-dependent lookup. We want to pass back
+ CP_ID_KIND_QUALIFIED for suppressing vtable lookup
+ (c++/37862), but none of the others. */
+ if (*idk != CP_ID_KIND_QUALIFIED)
+ *idk = CP_ID_KIND_NONE;
}
/* The `>' token might be the end of a template-id or
template-parameter-list now. */
= (build_new_method_call
(instance, fn, &args, NULL_TREE,
(idk == CP_ID_KIND_QUALIFIED
- ? LOOKUP_NONVIRTUAL : LOOKUP_NORMAL),
+ ? LOOKUP_NORMAL|LOOKUP_NONVIRTUAL
+ : LOOKUP_NORMAL),
/*fn_p=*/NULL,
tf_warning_or_error));
}
if (cp_parser_non_integral_constant_expression (parser, NIC_DEL))
return error_mark_node;
- return delete_sanity (expression, NULL_TREE, array_p, global_scope_p);
+ return delete_sanity (expression, NULL_TREE, array_p, global_scope_p,
+ tf_warning_or_error);
}
/* Returns true if TOKEN may start a cast-expression and false
return expr;
}
-/* Parse a trait expression. */
+/* Parse a trait expression.
+
+ Returns a representation of the expression, the underlying type
+ of the type at issue when KEYWORD is RID_UNDERLYING_TYPE. */
static tree
cp_parser_trait_expr (cp_parser* parser, enum rid keyword)
case RID_IS_ENUM:
kind = CPTK_IS_ENUM;
break;
+ case RID_IS_LITERAL_TYPE:
+ kind = CPTK_IS_LITERAL_TYPE;
+ break;
case RID_IS_POD:
kind = CPTK_IS_POD;
break;
case RID_IS_UNION:
kind = CPTK_IS_UNION;
break;
- case RID_IS_LITERAL_TYPE:
- kind = CPTK_IS_LITERAL_TYPE;
+ case RID_UNDERLYING_TYPE:
+ kind = CPTK_UNDERLYING_TYPE;
break;
default:
gcc_unreachable ();
/* Complete the trait expression, which may mean either processing
the trait expr now or saving it for template instantiation. */
- return finish_trait_expr (kind, type1, type2);
+ return kind != CPTK_UNDERLYING_TYPE
+ ? finish_trait_expr (kind, type1, type2)
+ : finish_underlying_type (type1);
}
/* Lambdas that appear in variable initializer or default argument scope
quals = (LAMBDA_EXPR_MUTABLE_P (lambda_expr)
? TYPE_UNQUALIFIED : TYPE_QUAL_CONST);
declarator = make_call_declarator (declarator, param_list, quals,
+ VIRT_SPEC_UNSPECIFIED,
exception_spec,
/*late_return_type=*/NULL_TREE);
declarator->id_loc = LAMBDA_EXPR_LOCATION (lambda_expr);
}
If RANGE_EXPR is an array:
- BEGIN_EXPR = __range
- END_EXPR = __range + ARRAY_SIZE(__range)
+ BEGIN_EXPR = __range
+ END_EXPR = __range + ARRAY_SIZE(__range)
+ Else if RANGE_EXPR has a member 'begin' or 'end':
+ BEGIN_EXPR = __range.begin()
+ END_EXPR = __range.end()
Else:
BEGIN_EXPR = begin(__range)
END_EXPR = end(__range);
- When calling begin()/end() we must use argument dependent
- lookup, but always considering 'std' as an associated namespace. */
+ If __range has a member 'begin' but not 'end', or vice versa, we must
+ still use the second alternative (it will surely fail, however).
+ When calling begin()/end() in the third alternative we must use
+ argument dependent lookup, but always considering 'std' as an associated
+ namespace. */
tree
cp_convert_range_for (tree statement, tree range_decl, tree range_expr)
else
{
/* Find out the type deduced by the declaration
- * `auto &&__range = range_expr' */
+ `auto &&__range = range_expr'. */
range_type = cp_build_reference_type (make_auto (), true);
range_type = do_auto_deduction (range_type, range_expr,
type_uses_auto (range_type));
- /* Create the __range variable */
+ /* Create the __range variable. */
range_temp = build_decl (input_location, VAR_DECL,
get_identifier ("__for_range"), range_type);
TREE_USED (range_temp) = 1;
LOOKUP_ONLYCONVERTING);
range_temp = convert_from_reference (range_temp);
-
- if (TREE_CODE (TREE_TYPE (range_temp)) == ARRAY_TYPE)
- {
- /* If RANGE_TEMP is an array we will use pointer arithmetic */
- iter_type = build_pointer_type (TREE_TYPE (TREE_TYPE (range_temp)));
- begin_expr = range_temp;
- end_expr
- = build_binary_op (input_location, PLUS_EXPR,
- range_temp,
- array_type_nelts_top (TREE_TYPE (range_temp)),
- 0);
- }
- else
- {
- /* If it is not an array, we must call begin(__range)/end__range() */
- VEC(tree,gc) *vec;
-
- begin_expr = get_identifier ("begin");
- vec = make_tree_vector ();
- VEC_safe_push (tree, gc, vec, range_temp);
- begin_expr = perform_koenig_lookup (begin_expr, vec,
- /*include_std=*/true);
- begin_expr = finish_call_expr (begin_expr, &vec, false, true,
- tf_warning_or_error);
- release_tree_vector (vec);
-
- end_expr = get_identifier ("end");
- vec = make_tree_vector ();
- VEC_safe_push (tree, gc, vec, range_temp);
- end_expr = perform_koenig_lookup (end_expr, vec,
- /*include_std=*/true);
- end_expr = finish_call_expr (end_expr, &vec, false, true,
- tf_warning_or_error);
- release_tree_vector (vec);
-
- /* The unqualified type of the __begin and __end temporaries should
- * be the same as required by the multiple auto declaration */
- iter_type = cv_unqualified (TREE_TYPE (begin_expr));
- if (!same_type_p (iter_type, cv_unqualified (TREE_TYPE (end_expr))))
- error ("inconsistent begin/end types in range-based for: %qT and %qT",
- TREE_TYPE (begin_expr), TREE_TYPE (end_expr));
- }
+ iter_type = cp_parser_perform_range_for_lookup (range_temp,
+ &begin_expr, &end_expr);
}
- /* The new for initialization statement */
+ /* The new for initialization statement. */
begin = build_decl (input_location, VAR_DECL,
get_identifier ("__for_begin"), iter_type);
TREE_USED (begin) = 1;
finish_for_init_stmt (statement);
-/* The new for condition */
+ /* The new for condition. */
condition = build_x_binary_op (NE_EXPR,
begin, ERROR_MARK,
end, ERROR_MARK,
NULL, tf_warning_or_error);
finish_for_cond (condition, statement);
- /* The new increment expression */
+ /* The new increment expression. */
expression = finish_unary_op_expr (PREINCREMENT_EXPR, begin);
finish_for_expr (expression, statement);
- /* The declaration is initialized with *__begin inside the loop body */
+ /* The declaration is initialized with *__begin inside the loop body. */
cp_finish_decl (range_decl,
build_x_indirect_ref (begin, RO_NULL, tf_warning_or_error),
/*is_constant_init*/false, NULL_TREE,
return statement;
}
+/* Solves BEGIN_EXPR and END_EXPR as described in cp_convert_range_for.
+ We need to solve both at the same time because the method used
+ depends on the existence of members begin or end.
+ Returns the type deduced for the iterator expression. */
+
+static tree
+cp_parser_perform_range_for_lookup (tree range, tree *begin, tree *end)
+{
+ if (!COMPLETE_TYPE_P (complete_type (TREE_TYPE (range))))
+ {
+ error ("range-based %<for%> expression of type %qT "
+ "has incomplete type", TREE_TYPE (range));
+ *begin = *end = error_mark_node;
+ return error_mark_node;
+ }
+ if (TREE_CODE (TREE_TYPE (range)) == ARRAY_TYPE)
+ {
+ /* If RANGE is an array, we will use pointer arithmetic. */
+ *begin = range;
+ *end = build_binary_op (input_location, PLUS_EXPR,
+ range,
+ array_type_nelts_top (TREE_TYPE (range)),
+ 0);
+ return build_pointer_type (TREE_TYPE (TREE_TYPE (range)));
+ }
+ else
+ {
+ /* If it is not an array, we must do a bit of magic. */
+ tree id_begin, id_end;
+ tree member_begin, member_end;
+
+ *begin = *end = error_mark_node;
+
+ id_begin = get_identifier ("begin");
+ id_end = get_identifier ("end");
+ member_begin = lookup_member (TREE_TYPE (range), id_begin,
+ /*protect=*/2, /*want_type=*/false);
+ member_end = lookup_member (TREE_TYPE (range), id_end,
+ /*protect=*/2, /*want_type=*/false);
+
+ if (member_begin != NULL_TREE || member_end != NULL_TREE)
+ {
+ /* Use the member functions. */
+ if (member_begin != NULL_TREE)
+ *begin = cp_parser_range_for_member_function (range, id_begin);
+ else
+ error ("range-based %<for%> expression of type %qT has an "
+ "%<end%> member but not a %<begin%>", TREE_TYPE (range));
+
+ if (member_end != NULL_TREE)
+ *end = cp_parser_range_for_member_function (range, id_end);
+ else
+ error ("range-based %<for%> expression of type %qT has a "
+ "%<begin%> member but not an %<end%>", TREE_TYPE (range));
+ }
+ else
+ {
+ /* Use global functions with ADL. */
+ VEC(tree,gc) *vec;
+ vec = make_tree_vector ();
+
+ VEC_safe_push (tree, gc, vec, range);
+
+ member_begin = perform_koenig_lookup (id_begin, vec,
+ /*include_std=*/true);
+ *begin = finish_call_expr (member_begin, &vec, false, true,
+ tf_warning_or_error);
+ member_end = perform_koenig_lookup (id_end, vec,
+ /*include_std=*/true);
+ *end = finish_call_expr (member_end, &vec, false, true,
+ tf_warning_or_error);
+
+ release_tree_vector (vec);
+ }
+
+ /* Last common checks. */
+ if (*begin == error_mark_node || *end == error_mark_node)
+ {
+ /* If one of the expressions is an error do no more checks. */
+ *begin = *end = error_mark_node;
+ return error_mark_node;
+ }
+ else
+ {
+ tree iter_type = cv_unqualified (TREE_TYPE (*begin));
+ /* The unqualified type of the __begin and __end temporaries should
+ be the same, as required by the multiple auto declaration. */
+ if (!same_type_p (iter_type, cv_unqualified (TREE_TYPE (*end))))
+ error ("inconsistent begin/end types in range-based %<for%> "
+ "statement: %qT and %qT",
+ TREE_TYPE (*begin), TREE_TYPE (*end));
+ return iter_type;
+ }
+ }
+}
+
+/* Helper function for cp_parser_perform_range_for_lookup.
+ Builds a tree for RANGE.IDENTIFIER(). */
+
+static tree
+cp_parser_range_for_member_function (tree range, tree identifier)
+{
+ tree member, res;
+ VEC(tree,gc) *vec;
+
+ member = finish_class_member_access_expr (range, identifier,
+ false, tf_warning_or_error);
+ if (member == error_mark_node)
+ return error_mark_node;
+
+ vec = make_tree_vector ();
+ res = finish_call_expr (member, &vec,
+ /*disallow_virtual=*/false,
+ /*koenig_p=*/false,
+ tf_warning_or_error);
+ release_tree_vector (vec);
+ return res;
+}
/* Parse an iteration-statement.
if (cxx_dialect < cxx0x)
{
error_at (cp_lexer_peek_token (parser->lexer)->location,
- "range-based-for loops are not allowed "
+ "range-based %<for%> loops are not allowed "
"in C++98 mode");
*decl = error_mark_node;
}
cp_decl_specifier_seq decl_specifiers;
tree extension_specifier = NULL_TREE;
+ timevar_push (TV_TEMPLATE_INST);
+
/* Look for an (optional) storage-class-specifier or
function-specifier. */
if (cp_parser_allow_gnu_extensions_p (parser))
end_explicit_instantiation ();
cp_parser_consume_semicolon_at_end_of_statement (parser);
+
+ timevar_pop (TV_TEMPLATE_INST);
}
/* Parse an explicit-specialization.
decltype ( expression )
char16_t
char32_t
+ __underlying_type ( type-id )
GNU Extension:
return type;
+ case RID_UNDERLYING_TYPE:
+ type = cp_parser_trait_expr (parser, RID_UNDERLYING_TYPE);
+
+ if (decl_specs)
+ cp_parser_set_decl_spec_type (decl_specs, type,
+ token->location,
+ /*user_defined_p=*/true);
+
+ return type;
+
default:
break;
}
elaborated-type-specifier. */
if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_BRACE))
{
+ timevar_push (TV_PARSE_ENUM);
if (nested_name_specifier)
{
/* The following catches invalid code such as:
if (scoped_enum_p)
finish_scope ();
+ timevar_pop (TV_PARSE_ENUM);
}
else
{
bool is_non_constant_init;
int ctor_dtor_or_conv_p;
bool friend_p;
- tree pushed_scope = NULL;
+ tree pushed_scope = NULL_TREE;
bool range_for_decl_p = false;
/* Gather the attributes that were provided with the
if (pushed_scope)
{
pop_scope (pushed_scope);
- pushed_scope = false;
+ pushed_scope = NULL_TREE;
}
decl = grokfield (declarator, decl_specifiers,
initializer, !is_non_constant_init,
if (member_p || cp_parser_parse_definitely (parser))
{
cp_cv_quals cv_quals;
+ cp_virt_specifiers virt_specifiers;
tree exception_specification;
tree late_return;
/* And the exception-specification. */
exception_specification
= cp_parser_exception_specification_opt (parser);
+ /* Parse the virt-specifier-seq. */
+ virt_specifiers = cp_parser_virt_specifier_seq_opt (parser);
late_return
= cp_parser_late_return_type_opt (parser);
declarator = make_call_declarator (declarator,
params,
cv_quals,
+ virt_specifiers,
exception_specification,
late_return);
/* Any subsequent parameter lists are to do with
return cv_quals;
}
+/* Parse an (optional) virt-specifier-seq.
+
+ virt-specifier-seq:
+ virt-specifier virt-specifier-seq [opt]
+
+ virt-specifier:
+ override
+ final
+
+ Returns a bitmask representing the virt-specifiers. */
+
+static cp_virt_specifiers
+cp_parser_virt_specifier_seq_opt (cp_parser* parser)
+{
+ cp_virt_specifiers virt_specifiers = VIRT_SPEC_UNSPECIFIED;
+
+ while (true)
+ {
+ cp_token *token;
+ cp_virt_specifiers virt_specifier;
+
+ /* Peek at the next token. */
+ token = cp_lexer_peek_token (parser->lexer);
+ /* See if it's a virt-specifier-qualifier. */
+ if (token->type != CPP_NAME)
+ break;
+ if (!strcmp (IDENTIFIER_POINTER(token->u.value), "override"))
+ virt_specifier = VIRT_SPEC_OVERRIDE;
+ else if (!strcmp (IDENTIFIER_POINTER(token->u.value), "final"))
+ virt_specifier = VIRT_SPEC_FINAL;
+ else
+ break;
+
+ if (virt_specifiers & virt_specifier)
+ {
+ error_at (token->location, "duplicate virt-specifier");
+ cp_lexer_purge_token (parser->lexer);
+ }
+ else
+ {
+ cp_lexer_consume_token (parser->lexer);
+ virt_specifiers |= virt_specifier;
+ }
+ }
+ return virt_specifiers;
+}
+
/* Parse a late-specified return type, if any. This is not a separate
non-terminal, but part of a function declarator, which looks like
Returns the TREE_TYPE representing the class. */
static tree
-cp_parser_class_specifier (cp_parser* parser)
+cp_parser_class_specifier_1 (cp_parser* parser)
{
tree type;
tree attributes = NULL_TREE;
return type;
}
+static tree
+cp_parser_class_specifier (cp_parser* parser)
+{
+ tree ret;
+ timevar_push (TV_PARSE_STRUCT);
+ ret = cp_parser_class_specifier_1 (parser);
+ timevar_pop (TV_PARSE_STRUCT);
+ return ret;
+}
+
/* Parse a class-head.
class-head:
class-key identifier [opt] base-clause [opt]
- class-key nested-name-specifier identifier base-clause [opt]
+ class-key nested-name-specifier identifier class-virt-specifier [opt] base-clause [opt]
class-key nested-name-specifier [opt] template-id
base-clause [opt]
+ class-virt-specifier:
+ final
+
GNU Extensions:
class-key attributes identifier [opt] base-clause [opt]
class-key attributes nested-name-specifier identifier base-clause [opt]
tree id = NULL_TREE;
tree type = NULL_TREE;
tree attributes;
+ cp_virt_specifiers virt_specifiers = VIRT_SPEC_UNSPECIFIED;
bool template_id_p = false;
bool qualified_p = false;
bool invalid_nested_name_p = false;
pop_deferring_access_checks ();
if (id)
- cp_parser_check_for_invalid_template_id (parser, id,
- type_start_token->location);
+ {
+ cp_parser_check_for_invalid_template_id (parser, id,
+ type_start_token->location);
+ virt_specifiers = cp_parser_virt_specifier_seq_opt (parser);
+ }
/* If it's not a `:' or a `{' then we can't really be looking at a
class-head, since a class-head only appears as part of a
/* At this point, we're going ahead with the class-specifier, even
if some other problem occurs. */
cp_parser_commit_to_tentative_parse (parser);
+ if (virt_specifiers & VIRT_SPEC_OVERRIDE)
+ {
+ cp_parser_error (parser,
+ "cannot specify %<override%> for a class");
+ type = error_mark_node;
+ goto out;
+ }
/* Issue the error about the overly-qualified name now. */
if (qualified_p)
{
if (type)
DECL_SOURCE_LOCATION (TYPE_NAME (type)) = type_start_token->location;
*attributes_p = attributes;
+ if (type && (virt_specifiers & VIRT_SPEC_FINAL))
+ CLASSTYPE_FINAL (type) = 1;
out:
parser->colon_corrects_to_scope_p = saved_colon_corrects_to_scope_p;
return type;
pop_nested_class ();
}
else
- fn = cp_parser_function_definition_after_declarator (parser,
+ {
+ timevar_id_t tv;
+ if (DECL_DECLARED_INLINE_P (current_function_decl))
+ tv = TV_PARSE_INLINE;
+ else
+ tv = TV_PARSE_FUNC;
+ timevar_push (tv);
+ fn = cp_parser_function_definition_after_declarator (parser,
/*inline_p=*/false);
+ timevar_pop (tv);
+ }
return fn;
}
static void
cp_parser_late_parsing_for_member (cp_parser* parser, tree member_function)
{
+ timevar_push (TV_PARSE_INMETH);
/* If this member is a template, get the underlying
FUNCTION_DECL. */
if (DECL_FUNCTION_TEMPLATE_P (member_function))
/* Restore the queue. */
pop_unparsed_function_queues (parser);
+ timevar_pop (TV_PARSE_INMETH);
}
/* If DECL contains any default args, remember it on the unparsed
cp_parser_objc_class_declaration (cp_parser* parser)
{
cp_lexer_consume_token (parser->lexer); /* Eat '@class'. */
- objc_declare_class (cp_parser_objc_identifier_list (parser));
+ while (true)
+ {
+ tree id;
+
+ id = cp_parser_identifier (parser);
+ if (id == error_mark_node)
+ break;
+
+ objc_declare_class (id);
+
+ if (cp_lexer_next_token_is (parser->lexer, CPP_COMMA))
+ cp_lexer_consume_token (parser->lexer);
+ else
+ break;
+ }
cp_parser_consume_semicolon_at_end_of_statement (parser);
}
token = cp_lexer_peek_token (parser->lexer);
continue;
}
- objc_start_method_definition (is_class_method, sig, attribute);
+ objc_start_method_definition (is_class_method, sig, attribute,
+ NULL_TREE);
/* For historical reasons, we accept an optional semicolon. */
if (cp_lexer_next_token_is (parser->lexer, CPP_SEMICOLON))
{
tok = cp_lexer_peek_token (parser->lexer);
error_at (tok->location, "identifier expected after %<@protocol%>");
- goto finish;
+ cp_parser_consume_semicolon_at_end_of_statement (parser);
+ return;
}
/* See if we have a forward declaration or a definition. */
/* Try a forward declaration first. */
if (tok->type == CPP_COMMA || tok->type == CPP_SEMICOLON)
{
- objc_declare_protocols (cp_parser_objc_identifier_list (parser),
- attributes);
- finish:
+ while (true)
+ {
+ tree id;
+
+ id = cp_parser_identifier (parser);
+ if (id == error_mark_node)
+ break;
+
+ objc_declare_protocol (id, attributes);
+
+ if(cp_lexer_next_token_is (parser->lexer, CPP_COMMA))
+ cp_lexer_consume_token (parser->lexer);
+ else
+ break;
+ }
cp_parser_consume_semicolon_at_end_of_statement (parser);
}
/* If decl is an iterator, preserve the operator on decl
until finish_omp_for. */
if (decl
- && (type_dependent_expression_p (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);
else