cp_debug_print_flag (file, "Colon doesn't start a class definition",
parser->colon_doesnt_start_class_def_p);
if (parser->type_definition_forbidden_message)
- fprintf (file, "Error message for forbidden type definitions: %s\n",
- parser->type_definition_forbidden_message);
+ fprintf (file, "Error message for forbidden type definitions: %s %s\n",
+ parser->type_definition_forbidden_message,
+ parser->type_definition_forbidden_message_arg
+ ? parser->type_definition_forbidden_message_arg : "<none>");
cp_debug_print_unparsed_queues (file, parser->unparsed_queues);
fprintf (file, "Number of class definitions in progress: %u\n",
parser->num_classes_being_defined);
static cp_expr cp_parser_braced_list
(cp_parser*, bool*);
static vec<constructor_elt, va_gc> *cp_parser_initializer_list
- (cp_parser *, bool *);
+ (cp_parser *, bool *, bool *);
static void cp_parser_ctor_initializer_opt_and_function_body
(cp_parser *, bool);
static tree cp_parser_global_scope_opt
(cp_parser *, bool);
static bool cp_parser_constructor_declarator_p
- (cp_parser *, bool);
+ (cp_parser *, cp_parser_flags, bool);
static tree cp_parser_function_definition_from_specifiers_and_declarator
(cp_parser *, cp_decl_specifier_seq *, tree, const cp_declarator *);
static tree cp_parser_function_definition_after_declarator
(cp_parser *);
static bool cp_parser_skip_to_closing_square_bracket
(cp_parser *);
+static size_t cp_parser_skip_balanced_tokens (cp_parser *, size_t);
/* Concept-related syntactic transformations */
if (parser->type_definition_forbidden_message)
{
/* Don't use `%s' to print the string, because quotations (`%<', `%>')
- in the message need to be interpreted. */
- error (parser->type_definition_forbidden_message);
+ or %qs in the message need to be interpreted. */
+ error (parser->type_definition_forbidden_message,
+ parser->type_definition_forbidden_message_arg);
return false;
}
return true;
decl);
if (DECL_CLASS_TEMPLATE_P (decl) && cxx_dialect < cxx17)
inform (location, "class template argument deduction is only available "
- "with -std=c++17 or -std=gnu++17");
+ "with %<-std=c++17%> or %<-std=gnu++17%>");
inform (DECL_SOURCE_LOCATION (decl), "%qD declared here", decl);
}
else if (TREE_CODE (id) == BIT_NOT_EXPR)
The user should have said "typename A<T>::X". */
if (cxx_dialect < cxx11 && id == ridpointers[(int)RID_CONSTEXPR])
inform (location, "C++11 %<constexpr%> only available with "
- "-std=c++11 or -std=gnu++11");
+ "%<-std=c++11%> or %<-std=gnu++11%>");
else if (cxx_dialect < cxx11 && id == ridpointers[(int)RID_NOEXCEPT])
inform (location, "C++11 %<noexcept%> only available with "
- "-std=c++11 or -std=gnu++11");
+ "%<-std=c++11%> or %<-std=gnu++11%>");
else if (cxx_dialect < cxx11
&& TREE_CODE (id) == IDENTIFIER_NODE
&& id_equal (id, "thread_local"))
inform (location, "C++11 %<thread_local%> only available with "
- "-std=c++11 or -std=gnu++11");
+ "%<-std=c++11%> or %<-std=gnu++11%>");
else if (!flag_concepts && id == ridpointers[(int)RID_CONCEPT])
- inform (location, "%<concept%> only available with -fconcepts");
+ inform (location, "%<concept%> only available with %<-fconcepts%>");
else if (processing_template_decl && current_class_type
&& TYPE_BINFO (current_class_type))
{
"GNU built-in suffix");
}
else if (!ext)
- inform (token->location, "use -fext-numeric-literals "
+ inform (token->location, "use %<-fext-numeric-literals%> "
"to enable more built-in suffixes");
if (kind == DK_ERROR)
&& cxx_dialect < cxx17
&& !in_system_header_at (input_location))
pedwarn (input_location, 0, "fold-expressions only available "
- "with -std=c++17 or -std=gnu++17");
+ "with %<-std=c++17%> or %<-std=gnu++17%>");
}
else
/* Let the front end know that this expression was
tree object_scope;
tree scope;
bool done;
+ location_t tilde_loc = token->location;
/* Consume the `~' token. */
cp_lexer_consume_token (parser->lexer);
}
gcc_assert (!scope || TYPE_P (scope));
+ token = cp_lexer_peek_token (parser->lexer);
+
+ /* Create a location with caret == start at the tilde,
+ finishing at the end of the peeked token, e.g:
+ ~token
+ ^~~~~~. */
+ location_t loc
+ = make_location (tilde_loc, tilde_loc, token->location);
+
/* If the name is of the form "X::~X" it's OK even if X is a
typedef. */
- token = cp_lexer_peek_token (parser->lexer);
+
if (scope
&& token->type == CPP_NAME
&& (cp_lexer_peek_nth_token (parser->lexer, 2)->type
&& constructor_name_p (token->u.value, scope))))
{
cp_lexer_consume_token (parser->lexer);
- return build_nt (BIT_NOT_EXPR, scope);
+ return cp_expr (build_nt (BIT_NOT_EXPR, scope), loc);
}
/* ~auto means the destructor of whatever the object is. */
if (cp_parser_is_keyword (token, RID_AUTO))
{
if (cxx_dialect < cxx14)
- pedwarn (input_location, 0,
+ pedwarn (loc, 0,
"%<~auto%> only available with "
- "-std=c++14 or -std=gnu++14");
+ "%<-std=c++14%> or %<-std=gnu++14%>");
cp_lexer_consume_token (parser->lexer);
- return build_nt (BIT_NOT_EXPR, make_auto ());
+ return cp_expr (build_nt (BIT_NOT_EXPR, make_auto (), loc));
}
/* If there was an explicit qualification (S::~T), first look
type_decl = cp_parser_identifier (parser);
if (type_decl != error_mark_node)
type_decl = build_nt (BIT_NOT_EXPR, type_decl);
- return type_decl;
+ return cp_expr (type_decl, loc);
}
}
/* If an error occurred, assume that the name of the
if (declarator_p && scope && !check_dtor_name (scope, type_decl))
{
if (!cp_parser_uncommitted_to_tentative_parse_p (parser))
- error_at (token->location,
+ error_at (loc,
"declaration of %<~%T%> as member of %qT",
type_decl, scope);
cp_parser_simulate_error (parser);
&& !DECL_IMPLICIT_TYPEDEF_P (type_decl)
&& !DECL_SELF_REFERENCE_P (type_decl)
&& !cp_parser_uncommitted_to_tentative_parse_p (parser))
- error_at (token->location,
+ error_at (loc,
"typedef-name %qD used as destructor declarator",
type_decl);
- return build_nt (BIT_NOT_EXPR, TREE_TYPE (type_decl));
+ return cp_expr (build_nt (BIT_NOT_EXPR, TREE_TYPE (type_decl), loc));
}
case CPP_KEYWORD:
if (cxx_dialect < cxx14)
pedwarn (input_location, 0,
"%<~auto%> only available with "
- "-std=c++14 or -std=gnu++14");
+ "%<-std=c++14%> or %<-std=gnu++14%>");
cp_lexer_consume_token (parser->lexer);
cp_lexer_consume_token (parser->lexer);
*scope = NULL_TREE;
/* Types cannot be defined in a `sizeof' expression. Save away the
old message. */
const char *saved_message = parser->type_definition_forbidden_message;
- /* And create the new one. */
- const int kwd = RID_BUILTIN_HAS_ATTRIBUTE;
- char *tmp = concat ("types may not be defined in %<",
- IDENTIFIER_POINTER (ridpointers[kwd]),
- "%> expressions", NULL);
- parser->type_definition_forbidden_message = tmp;
+ const char *saved_message_arg
+ = parser->type_definition_forbidden_message_arg;
+ parser->type_definition_forbidden_message
+ = G_("types may not be defined in %qs expressions");
+ parser->type_definition_forbidden_message_arg
+ = IDENTIFIER_POINTER (ridpointers[RID_BUILTIN_HAS_ATTRIBUTE]);
/* The restrictions on constant-expressions do not apply inside
sizeof expressions. */
cp_parser_parse_definitely (parser);
/* If the type-id production did not work out, then we must be
- looking at the unary-expression production. */
+ looking at an expression. */
if (!oper || oper == error_mark_node)
- oper = cp_parser_unary_expression (parser);
+ oper = cp_parser_assignment_expression (parser);
STRIP_ANY_LOCATION_WRAPPER (oper);
--cp_unevaluated_operand;
--c_inhibit_evaluation_warnings;
- /* Free the message we created. */
- free (tmp);
/* And restore the old one. */
parser->type_definition_forbidden_message = saved_message;
+ parser->type_definition_forbidden_message_arg = saved_message_arg;
parser->integral_constant_expression_p
= saved_integral_constant_expression_p;
parser->non_integral_constant_expression_p
{
cp_parser_expression_stack stack;
cp_parser_expression_stack_entry *sp = &stack[0];
+ cp_parser_expression_stack_entry *disable_warnings_sp = NULL;
cp_parser_expression_stack_entry current;
cp_expr rhs;
cp_token *token;
/* For "false && x" or "true || x", x will never be executed;
disable warnings while evaluating it. */
- if (current.tree_type == TRUTH_ANDIF_EXPR)
- c_inhibit_evaluation_warnings +=
- cp_fully_fold (current.lhs) == truthvalue_false_node;
- else if (current.tree_type == TRUTH_ORIF_EXPR)
- c_inhibit_evaluation_warnings +=
- cp_fully_fold (current.lhs) == truthvalue_true_node;
+ if ((current.tree_type == TRUTH_ANDIF_EXPR
+ && cp_fully_fold (current.lhs) == truthvalue_false_node)
+ || (current.tree_type == TRUTH_ORIF_EXPR
+ && cp_fully_fold (current.lhs) == truthvalue_true_node))
+ {
+ disable_warnings_sp = sp;
+ ++c_inhibit_evaluation_warnings;
+ }
/* Extract another operand. It may be the RHS of this expression
or the LHS of a new, higher priority expression. */
}
/* Undo the disabling of warnings done above. */
- if (current.tree_type == TRUTH_ANDIF_EXPR)
- c_inhibit_evaluation_warnings -=
- cp_fully_fold (current.lhs) == truthvalue_false_node;
- else if (current.tree_type == TRUTH_ORIF_EXPR)
- c_inhibit_evaluation_warnings -=
- cp_fully_fold (current.lhs) == truthvalue_true_node;
+ if (sp == disable_warnings_sp)
+ {
+ disable_warnings_sp = NULL;
+ --c_inhibit_evaluation_warnings;
+ }
if (warn_logical_not_paren
&& TREE_CODE_CLASS (current.tree_type) == tcc_comparison
{
const char *saved_message = parser->type_definition_forbidden_message;
parser->type_definition_forbidden_message
- = G_("types may not be defined within __builtin_offsetof");
+ = G_("types may not be defined within %<__builtin_offsetof%>");
type = cp_parser_type_id (parser);
parser->type_definition_forbidden_message = saved_message;
}
{
error_at (LAMBDA_EXPR_LOCATION (lambda_expr),
"lambda-expression in unevaluated context"
- " only available with -std=c++2a or -std=gnu++2a");
+ " only available with %<-std=c++2a%> or %<-std=gnu++2a%>");
token->error_reported = true;
}
ok = false;
}
- else if (parser->in_template_argument_list_p)
+ else if (parser->in_template_argument_list_p || processing_template_parmlist)
{
if (!token->error_reported)
{
error_at (token->location, "lambda-expression in template-argument"
- " only available with -std=c++2a or -std=gnu++2a");
+ " only available with %<-std=c++2a%> or %<-std=gnu++2a%>");
token->error_reported = true;
}
ok = false;
parser->implicit_template_scope = 0;
parser->auto_is_implicit_function_template_parm_p = false;
+ /* The body of a lambda in a discarded statement is not discarded. */
+ bool discarded = in_discarded_stmt;
+ in_discarded_stmt = 0;
+
/* By virtue of defining a local class, a lambda expression has access to
the private variables of enclosing classes. */
type = finish_struct (type, /*attributes=*/NULL_TREE);
+ in_discarded_stmt = discarded;
+
parser->num_template_parameter_lists = saved_num_template_parameter_lists;
parser->in_statement = in_statement;
parser->in_switch_statement_p = in_switch_statement_p;
error ("non-local lambda expression cannot have a capture-default");
}
+ hash_set<tree, true> ids;
+ tree first_capture_id = NULL_TREE;
while (cp_lexer_next_token_is_not (parser->lexer, CPP_CLOSE_SQUARE))
{
cp_token* capture_token;
pedwarn (loc, 0, "explicit by-copy capture of %<this%> redundant "
"with by-copy capture default");
cp_lexer_consume_token (parser->lexer);
- add_capture (lambda_expr,
- /*id=*/this_identifier,
- /*initializer=*/finish_this_expr (),
- /*by_reference_p=*/true,
- explicit_init_p);
+ if (LAMBDA_EXPR_THIS_CAPTURE (lambda_expr))
+ pedwarn (input_location, 0,
+ "already captured %qD in lambda expression",
+ this_identifier);
+ else
+ add_capture (lambda_expr, /*id=*/this_identifier,
+ /*initializer=*/finish_this_expr (),
+ /*by_reference_p=*/true, explicit_init_p);
continue;
}
location_t loc = cp_lexer_peek_token (parser->lexer)->location;
if (cxx_dialect < cxx17)
pedwarn (loc, 0, "%<*this%> capture only available with "
- "-std=c++17 or -std=gnu++17");
+ "%<-std=c++17%> or %<-std=gnu++17%>");
cp_lexer_consume_token (parser->lexer);
cp_lexer_consume_token (parser->lexer);
- add_capture (lambda_expr,
- /*id=*/this_identifier,
- /*initializer=*/finish_this_expr (),
- /*by_reference_p=*/false,
- explicit_init_p);
+ if (LAMBDA_EXPR_THIS_CAPTURE (lambda_expr))
+ pedwarn (input_location, 0,
+ "already captured %qD in lambda expression",
+ this_identifier);
+ else
+ add_capture (lambda_expr, /*id=*/this_identifier,
+ /*initializer=*/finish_this_expr (),
+ /*by_reference_p=*/false, explicit_init_p);
continue;
}
bool init_pack_expansion = false;
+ location_t ellipsis_loc = UNKNOWN_LOCATION;
if (cp_lexer_next_token_is (parser->lexer, CPP_ELLIPSIS))
{
- location_t loc = cp_lexer_peek_token (parser->lexer)->location;
+ ellipsis_loc = cp_lexer_peek_token (parser->lexer)->location;
if (cxx_dialect < cxx2a)
- pedwarn (loc, 0, "pack init-capture only available with "
- "-std=c++2a or -std=gnu++2a");
+ pedwarn (ellipsis_loc, 0, "pack init-capture only available with "
+ "%<-std=c++2a%> or %<-std=gnu++2a%>");
cp_lexer_consume_token (parser->lexer);
init_pack_expansion = true;
}
if (cxx_dialect < cxx14)
pedwarn (input_location, 0,
"lambda capture initializers "
- "only available with -std=c++14 or -std=gnu++14");
+ "only available with %<-std=c++14%> or %<-std=gnu++14%>");
capture_init_expr = cp_parser_initializer (parser, &direct,
&non_constant, true);
explicit_init_p = true;
if (cp_lexer_next_token_is (parser->lexer, CPP_ELLIPSIS))
{
+ location_t loc = cp_lexer_peek_token (parser->lexer)->location;
cp_lexer_consume_token (parser->lexer);
capture_init_expr = make_pack_expansion (capture_init_expr);
+ if (init_pack_expansion)
+ {
+ /* If what follows is an initializer, the second '...' is
+ invalid. But for cases like [...xs...], the first one
+ is invalid. */
+ if (cp_lexer_next_token_is (parser->lexer, CPP_EQ)
+ || cp_lexer_next_token_is (parser->lexer, CPP_OPEN_PAREN)
+ || cp_lexer_next_token_is (parser->lexer, CPP_OPEN_BRACE))
+ ellipsis_loc = loc;
+ error_at (ellipsis_loc, "too many %<...%> in lambda capture");
+ continue;
+ }
}
}
"default", capture_id);
}
- add_capture (lambda_expr,
- capture_id,
- capture_init_expr,
- /*by_reference_p=*/capture_kind == BY_REFERENCE,
- explicit_init_p);
+ /* Check for duplicates.
+ Optimize for the zero or one explicit captures cases and only create
+ the hash_set after adding second capture. */
+ bool found = false;
+ if (ids.elements ())
+ found = ids.add (capture_id);
+ else if (first_capture_id == NULL_TREE)
+ first_capture_id = capture_id;
+ else if (capture_id == first_capture_id)
+ found = true;
+ else
+ {
+ ids.add (first_capture_id);
+ ids.add (capture_id);
+ }
+ if (found)
+ pedwarn (input_location, 0,
+ "already captured %qD in lambda expression", capture_id);
+ else
+ add_capture (lambda_expr, capture_id, capture_init_expr,
+ /*by_reference_p=*/capture_kind == BY_REFERENCE,
+ explicit_init_p);
/* If there is any qualification still in effect, clear it
now; we will be starting fresh with the next capture. */
This means an empty parameter list, no attributes, and no exception
specification. */
tree param_list = void_list_node;
- tree attributes = NULL_TREE;
+ tree std_attrs = NULL_TREE;
+ tree gnu_attrs = NULL_TREE;
tree exception_spec = NULL_TREE;
tree template_param_list = NULL_TREE;
tree tx_qual = NULL_TREE;
if (cxx_dialect < cxx14)
pedwarn (parser->lexer->next_token->location, 0,
"lambda templates are only available with "
- "-std=c++14 or -std=gnu++14");
+ "%<-std=c++14%> or %<-std=gnu++14%>");
else if (cxx_dialect < cxx2a)
pedwarn (parser->lexer->next_token->location, OPT_Wpedantic,
"lambda templates are only available with "
- "-std=c++2a or -std=gnu++2a");
+ "%<-std=c++2a%> or %<-std=gnu++2a%>");
cp_lexer_consume_token (parser->lexer);
++parser->num_template_parameter_lists;
}
+ /* Committee discussion supports allowing attributes here. */
+ lambda_specs.attributes = cp_parser_attributes_opt (parser);
+
/* The parameter-declaration-clause is optional (unless
template-parameter-list was given), but must begin with an
opening parenthesis if present. */
/* In the decl-specifier-seq of the lambda-declarator, each
decl-specifier shall either be mutable or constexpr. */
int declares_class_or_enum;
- if (cp_lexer_next_token_is_decl_specifier_keyword (parser->lexer))
+ if (cp_lexer_next_token_is_decl_specifier_keyword (parser->lexer)
+ && !cp_next_tokens_can_be_gnu_attribute_p (parser))
cp_parser_decl_specifier_seq (parser,
CP_PARSER_FLAGS_ONLY_MUTABLE_OR_CONSTEXPR,
&lambda_specs, &declares_class_or_enum);
/* Parse optional exception specification. */
exception_spec = cp_parser_exception_specification_opt (parser);
- attributes = cp_parser_std_attribute_spec_seq (parser);
+ /* GCC 8 accepted attributes here, and this is the place for standard
+ C++11 attributes that appertain to the function type. */
+ if (cp_next_tokens_can_be_gnu_attribute_p (parser))
+ gnu_attrs = cp_parser_gnu_attributes_opt (parser);
+ else
+ std_attrs = cp_parser_std_attribute_spec_seq (parser);
/* Parse optional trailing return type. */
if (cp_lexer_next_token_is (parser->lexer, CPP_DEREF))
return_type = cp_parser_trailing_type_id (parser);
}
+ /* Also allow GNU attributes at the very end of the declaration, the
+ usual place for GNU attributes. */
+ if (cp_next_tokens_can_be_gnu_attribute_p (parser))
+ gnu_attrs = chainon (gnu_attrs, cp_parser_gnu_attributes_opt (parser));
+
/* The function parameters must be in scope all the way until after the
trailing-return-type in case of decltype. */
pop_bindings_and_leave_scope ();
= lambda_specs.locations[ds_constexpr];
else
error_at (lambda_specs.locations[ds_constexpr], "%<constexpr%> "
- "lambda only available with -std=c++17 or -std=gnu++17");
+ "lambda only available with %<-std=c++17%> or "
+ "%<-std=gnu++17%>");
}
p = obstack_alloc (&declarator_obstack, 0);
exception_spec,
return_type,
/*requires_clause*/NULL_TREE);
- declarator->std_attributes = attributes;
+ declarator->std_attributes = std_attrs;
fco = grokmethod (&return_type_specs,
declarator,
- NULL_TREE);
+ chainon (gnu_attrs, lambda_specs.attributes));
if (fco != error_mark_node)
{
DECL_INITIALIZED_IN_CLASS_P (fco) = 1;
{
tree statement, std_attrs = NULL_TREE;
cp_token *token;
- location_t statement_location, attrs_location;
+ location_t statement_location, attrs_loc;
restart:
if (if_p != NULL)
statement = NULL_TREE;
saved_token_sentinel saved_tokens (parser->lexer);
- attrs_location = cp_lexer_peek_token (parser->lexer)->location;
+ attrs_loc = cp_lexer_peek_token (parser->lexer)->location;
if (c_dialect_objc ())
/* In obj-c++, seeing '[[' might be the either the beginning of
c++11 attributes, or a nested objc-message-expression. So
let's parse the c++11 attributes tentatively. */
cp_parser_parse_tentatively (parser);
std_attrs = cp_parser_std_attribute_spec_seq (parser);
+ if (std_attrs)
+ {
+ location_t end_loc
+ = cp_lexer_previous_token (parser->lexer)->location;
+ attrs_loc = make_location (attrs_loc, attrs_loc, end_loc);
+ }
if (c_dialect_objc ())
{
if (!cp_parser_parse_definitely (parser))
case RID_IF:
case RID_SWITCH:
- std_attrs = process_stmt_hotness_attribute (std_attrs);
+ std_attrs = process_stmt_hotness_attribute (std_attrs, attrs_loc);
statement = cp_parser_selection_statement (parser, if_p, chain);
break;
case RID_WHILE:
case RID_DO:
case RID_FOR:
- std_attrs = process_stmt_hotness_attribute (std_attrs);
+ std_attrs = process_stmt_hotness_attribute (std_attrs, attrs_loc);
statement = cp_parser_iteration_statement (parser, if_p, false, 0);
break;
case RID_CONTINUE:
case RID_RETURN:
case RID_GOTO:
- std_attrs = process_stmt_hotness_attribute (std_attrs);
+ std_attrs = process_stmt_hotness_attribute (std_attrs, attrs_loc);
statement = cp_parser_jump_statement (parser);
break;
case RID_AT_FINALLY:
case RID_AT_SYNCHRONIZED:
case RID_AT_THROW:
- std_attrs = process_stmt_hotness_attribute (std_attrs);
+ std_attrs = process_stmt_hotness_attribute (std_attrs, attrs_loc);
statement = cp_parser_objc_statement (parser);
break;
case RID_TRY:
- std_attrs = process_stmt_hotness_attribute (std_attrs);
+ std_attrs = process_stmt_hotness_attribute (std_attrs, attrs_loc);
statement = cp_parser_try_block (parser);
break;
case RID_SYNCHRONIZED:
case RID_ATOMIC_NOEXCEPT:
case RID_ATOMIC_CANCEL:
- std_attrs = process_stmt_hotness_attribute (std_attrs);
+ std_attrs = process_stmt_hotness_attribute (std_attrs, attrs_loc);
statement = cp_parser_transaction (parser, token);
break;
case RID_TRANSACTION_CANCEL:
- std_attrs = process_stmt_hotness_attribute (std_attrs);
+ std_attrs = process_stmt_hotness_attribute (std_attrs, attrs_loc);
statement = cp_parser_transaction_cancel (parser);
break;
if (loc_after_labels != NULL)
*loc_after_labels = statement_location;
- std_attrs = process_stmt_hotness_attribute (std_attrs);
+ std_attrs = process_stmt_hotness_attribute (std_attrs, attrs_loc);
/* Look for an expression-statement instead. */
statement = cp_parser_expression_statement (parser, in_statement_expr);
/* Allow "[[fallthrough]];", but warn otherwise. */
if (std_attrs != NULL_TREE)
- warning_at (attrs_location,
+ warning_at (attrs_loc,
OPT_Wattributes,
"attributes at the beginning of statement are ignored");
}
cp_token *tok = cp_lexer_consume_token (parser->lexer);
if (cxx_dialect < cxx17 && !in_system_header_at (tok->location))
pedwarn (tok->location, 0, "%<if constexpr%> only available "
- "with -std=c++17 or -std=gnu++17");
+ "with %<-std=c++17%> or %<-std=gnu++17%>");
}
/* Look for the `('. */
if (cxx_dialect < cxx17)
pedwarn (cp_lexer_peek_token (parser->lexer)->location, 0,
"init-statement in selection statements only available "
- "with -std=c++17 or -std=gnu++17");
+ "with %<-std=c++17%> or %<-std=gnu++17%>");
cp_parser_init_statement (parser, &decl);
}
{
pedwarn (cp_lexer_peek_token (parser->lexer)->location, 0,
"range-based %<for%> loops with initializer only "
- "available with -std=c++2a or -std=gnu++2a");
+ "available with %<-std=c++2a%> or %<-std=gnu++2a%>");
*decl = error_mark_node;
}
}
if (cxx_dialect < cxx11)
pedwarn (cp_lexer_peek_token (parser->lexer)->location, 0,
"range-based %<for%> loops only available with "
- "-std=c++11 or -std=gnu++11");
+ "%<-std=c++11%> or %<-std=gnu++11%>");
}
else
/* The ';' is not consumed yet because we told
if ((decl != error_mark_node
&& DECL_INITIAL (decl) != error_mark_node)
|| cp_parser_uncommitted_to_tentative_parse_p (parser))
- cp_parser_error (parser, "expected %<,%> or %<;%>");
+ cp_parser_error (parser, "expected %<;%>");
/* Skip tokens until we reach the end of the statement. */
cp_parser_skip_to_end_of_statement (parser);
/* If the next token is now a `;', consume it. */
if (cxx_dialect < cxx17)
pedwarn (loc, 0, "structured bindings only available with "
- "-std=c++17 or -std=gnu++17");
+ "%<-std=c++17%> or %<-std=gnu++17%>");
tree pushed_scope;
cp_declarator *declarator = make_declarator (cdk_decomp);
case RID_CONCEPT:
ds = ds_concept;
cp_lexer_consume_token (parser->lexer);
+
+ if (flags & CP_PARSER_FLAGS_ONLY_MUTABLE_OR_CONSTEXPR)
+ break;
+
+ /* In C++20 a concept definition is just 'concept name = expr;'
+ Support that syntax by pretending we've seen 'bool'. */
+ if (cp_lexer_next_token_is (parser->lexer, CPP_NAME)
+ && cp_lexer_nth_token_is (parser->lexer, 2, CPP_EQ))
+ {
+ cp_parser_set_decl_spec_type (decl_specs, boolean_type_node,
+ token, /*type_definition*/false);
+ decl_specs->any_type_specifiers_p = true;
+ }
break;
/* function-specifier:
ds = ds_typedef;
/* Consume the token. */
cp_lexer_consume_token (parser->lexer);
+
+ if (flags & CP_PARSER_FLAGS_ONLY_MUTABLE_OR_CONSTEXPR)
+ break;
+
/* A constructor declarator cannot appear in a typedef. */
constructor_possible_p = false;
/* The "typedef" keyword can only occur in a declaration; we
= (!found_decl_spec
&& constructor_possible_p
&& (cp_parser_constructor_declarator_p
- (parser, decl_spec_seq_has_spec_p (decl_specs, ds_friend))));
+ (parser, flags, decl_spec_seq_has_spec_p (decl_specs,
+ ds_friend))));
/* If we don't have a DECL_SPEC yet, then we must be looking at
a type-specifier. */
bool is_cv_qualifier;
tree type_spec;
+ if (flags & CP_PARSER_FLAGS_ONLY_MUTABLE_OR_CONSTEXPR)
+ flags |= CP_PARSER_FLAGS_NO_TYPE_DEFINITIONS;
+
type_spec
= cp_parser_type_specifier (parser, flags,
decl_specs,
if (cxx_dialect < cxx2a)
pedwarn (token->location, 0,
- "%<explicit(bool)%> only available with -std=c++2a "
- "or -std=gnu++2a");
+ "%<explicit(bool)%> only available with %<-std=c++2a%> "
+ "or %<-std=gnu++2a%>");
/* Parse the constant-expression. */
expr = cp_parser_constant_expression (parser);
if (cxx_dialect < cxx17)
pedwarn (input_location, OPT_Wpedantic,
"static_assert without a message "
- "only available with -std=c++17 or -std=gnu++17");
+ "only available with %<-std=c++17%> or %<-std=gnu++17%>");
/* Eat the ')' */
cp_lexer_consume_token (parser->lexer);
message = build_string (1, "");
{
if (TREE_DEPRECATED (decl)
&& deprecated_state != DEPRECATED_SUPPRESS)
- warn_deprecated_use (decl, NULL_TREE);
+ {
+ tree d = DECL_TEMPLATE_RESULT (decl);
+ tree attr;
+ if (TREE_CODE (d) == TYPE_DECL)
+ attr = lookup_attribute ("deprecated",
+ TYPE_ATTRIBUTES (TREE_TYPE (d)));
+ else
+ attr = lookup_attribute ("deprecated",
+ DECL_ATTRIBUTES (d));
+ warn_deprecated_use (decl, attr);
+ }
}
else
{
error_at (token->location,
"use of %<auto%> in lambda parameter declaration "
"only available with "
- "-std=c++14 or -std=gnu++14");
+ "%<-std=c++14%> or %<-std=gnu++14%>");
}
else if (cxx_dialect < cxx14)
error_at (token->location,
"use of %<auto%> in parameter declaration "
"only available with "
- "-std=c++14 or -std=gnu++14");
+ "%<-std=c++14%> or %<-std=gnu++14%>");
else if (!flag_concepts)
pedwarn (token->location, 0,
"use of %<auto%> in parameter declaration "
- "only available with -fconcepts");
+ "only available with %<-fconcepts%>");
}
else
type = make_auto ();
if (TREE_CODE (type) == TYPENAME_TYPE)
warning (OPT_Wattributes,
"attributes ignored on uninstantiated type");
- else if (tag_type != enum_type && CLASSTYPE_TEMPLATE_INSTANTIATION (type)
+ else if (tag_type != enum_type
+ && TREE_CODE (type) != BOUND_TEMPLATE_TEMPLATE_PARM
+ && CLASSTYPE_TEMPLATE_INSTANTIATION (type)
&& ! processing_explicit_instantiation)
warning (OPT_Wattributes,
"attributes ignored on template instantiation");
bool is_unnamed = false;
tree underlying_type = NULL_TREE;
cp_token *type_start_token = NULL;
- bool saved_colon_corrects_to_scope_p = parser->colon_corrects_to_scope_p;
-
- parser->colon_corrects_to_scope_p = false;
+ temp_override<bool> cleanup (parser->colon_corrects_to_scope_p, false);
/* Parse tentatively so that we can back up if we don't find a
enum-specifier. */
push_deferring_access_checks (dk_no_check);
nested_name_specifier
- = cp_parser_nested_name_specifier_opt (parser,
- /*typename_keyword_p=*/true,
- /*check_dependency_p=*/false,
- /*type_p=*/false,
- /*is_declaration=*/false);
+ = cp_parser_nested_name_specifier_opt (parser,
+ /*typename_keyword_p=*/true,
+ /*check_dependency_p=*/false,
+ /*type_p=*/false,
+ /*is_declaration=*/false);
if (nested_name_specifier)
{
tree name;
identifier = cp_parser_identifier (parser);
- name = cp_parser_lookup_name (parser, identifier,
- enum_type,
- /*is_template=*/false,
- /*is_namespace=*/false,
- /*check_dependency=*/true,
- /*ambiguous_decls=*/NULL,
- input_location);
+ name = cp_parser_lookup_name (parser, identifier,
+ enum_type,
+ /*is_template=*/false,
+ /*is_namespace=*/false,
+ /*check_dependency=*/true,
+ /*ambiguous_decls=*/NULL,
+ input_location);
if (name && name != error_mark_node)
{
type = TREE_TYPE (name);
{
if (cxx_dialect < cxx11 || (!scoped_enum_p && !underlying_type))
{
+ if (has_underlying_type)
+ cp_parser_commit_to_tentative_parse (parser);
cp_parser_error (parser, "expected %<{%>");
if (has_underlying_type)
- {
- type = NULL_TREE;
- goto out;
- }
+ return error_mark_node;
}
/* An opaque-enum-specifier must have a ';' here. */
if ((scoped_enum_p || underlying_type)
&& cp_lexer_next_token_is_not (parser->lexer, CPP_SEMICOLON))
{
+ if (has_underlying_type)
+ cp_parser_commit_to_tentative_parse (parser);
cp_parser_error (parser, "expected %<;%> or %<{%>");
if (has_underlying_type)
- {
- type = NULL_TREE;
- goto out;
- }
+ return error_mark_node;
}
}
push_scope (nested_name_specifier);
}
else if (TREE_CODE (nested_name_specifier) == NAMESPACE_DECL)
- {
- push_nested_namespace (nested_name_specifier);
- }
+ push_nested_namespace (nested_name_specifier);
}
/* Issue an error message if type-definitions are forbidden here. */
pop_scope (nested_name_specifier);
}
else if (TREE_CODE (nested_name_specifier) == NAMESPACE_DECL)
- {
- pop_nested_namespace (nested_name_specifier);
- }
+ pop_nested_namespace (nested_name_specifier);
}
- out:
- parser->colon_corrects_to_scope_p = saved_colon_corrects_to_scope_p;
return type;
}
if (cxx_dialect < cxx2a)
pedwarn (cp_lexer_peek_token (parser->lexer)->location,
OPT_Wpedantic, "nested inline namespace definitions only "
- "available with -std=c++2a or -std=gnu++2a");
+ "available with %<-std=c++2a%> or %<-std=gnu++2a%>");
cp_lexer_consume_token (parser->lexer);
}
if (!nested_definition_count && cxx_dialect < cxx17)
pedwarn (input_location, OPT_Wpedantic,
- "nested namespace definitions only available with "
- "-std=c++17 or -std=gnu++17");
+ "nested namespace definitions only available with "
+ "%<-std=c++17%> or %<-std=gnu++17%>");
/* Nested namespace names can create new namespaces (unlike
other qualified-ids). */
/*is_declaration=*/true);
if (!qscope)
qscope = global_namespace;
- else if (UNSCOPED_ENUM_P (qscope))
+ else if (UNSCOPED_ENUM_P (qscope)
+ && !TYPE_FUNCTION_SCOPE_P (qscope))
qscope = CP_TYPE_CONTEXT (qscope);
if (access_declaration_p && cp_parser_error_occurred (parser))
&& !in_system_header_at (ell->location))
pedwarn (ell->location, 0,
"pack expansion in using-declaration only available "
- "with -std=c++17 or -std=gnu++17");
+ "with %<-std=c++17%> or %<-std=gnu++17%>");
qscope = make_pack_expansion (qscope);
}
if (cxx_dialect < cxx17)
pedwarn (comma->location, 0,
"comma-separated list in using-declaration only available "
- "with -std=c++17 or -std=gnu++17");
+ "with %<-std=c++17%> or %<-std=gnu++17%>");
goto again;
}
location_t volatile_loc = UNKNOWN_LOCATION;
location_t inline_loc = UNKNOWN_LOCATION;
location_t goto_loc = UNKNOWN_LOCATION;
+ location_t first_loc = UNKNOWN_LOCATION;
- if (cp_parser_allow_gnu_extensions_p (parser) && parser->in_function_body)
+ if (cp_parser_allow_gnu_extensions_p (parser))
for (;;)
{
cp_token *token = cp_lexer_peek_token (parser->lexer);
inform (volatile_loc, "first seen here");
}
else
- volatile_loc = loc;
+ {
+ if (!parser->in_function_body)
+ warning_at (loc, 0, "asm qualifier %qT ignored outside of "
+ "function body", token->u.value);
+ volatile_loc = loc;
+ }
cp_lexer_consume_token (parser->lexer);
continue;
}
else
inline_loc = loc;
+ if (!first_loc)
+ first_loc = loc;
cp_lexer_consume_token (parser->lexer);
continue;
}
else
goto_loc = loc;
+ if (!first_loc)
+ first_loc = loc;
cp_lexer_consume_token (parser->lexer);
continue;
bool inline_p = (inline_loc != UNKNOWN_LOCATION);
bool goto_p = (goto_loc != UNKNOWN_LOCATION);
+ if (!parser->in_function_body && (inline_p || goto_p))
+ {
+ error_at (first_loc, "asm qualifier outside of function body");
+ inline_p = goto_p = false;
+ }
+
/* Look for the opening `('. */
if (!cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN))
return;
{
/* Handle C++17 deduction guides. */
if (!decl_specifiers->type
+ && !decl_specifiers->any_type_specifiers_p
&& ctor_dtor_or_conv_p <= 0
&& cxx_dialect >= cxx17)
{
tree decl
= cp_parser_lookup_name_simple (parser, unqualified_name,
token->location);
- if (!is_overloaded_fn (decl))
+ if (!is_overloaded_fn (decl)
+ /* Allow
+ template<typename T>
+ A<T>::A(T::type) { } */
+ && !(MAYBE_CLASS_TYPE_P (qualifying_scope)
+ && constructor_name_p (unqualified_name,
+ qualifying_scope)))
flags &= ~CP_PARSER_FLAGS_TYPENAME_OPTIONAL;
}
}
/* Check for attributes first. */
if (cp_next_tokens_can_be_attribute_p (parser))
{
+ /* GNU attributes at the end of a declaration apply to the
+ declaration as a whole, not to the trailing return type. So look
+ ahead to see if these attributes are at the end. */
+ if (seen_type_specifier && is_trailing_return
+ && cp_next_tokens_can_be_gnu_attribute_p (parser))
+ {
+ size_t n = cp_parser_skip_attributes_opt (parser, 1);
+ cp_token *tok = cp_lexer_peek_nth_token (parser->lexer, n);
+ if (tok->type == CPP_SEMICOLON || tok->type == CPP_COMMA
+ || tok->type == CPP_EQ || tok->type == CPP_OPEN_BRACE)
+ break;
+ }
type_specifier_seq->attributes
= attr_chainon (type_specifier_seq->attributes,
cp_parser_attributes_opt (parser));
bool in_function_try_block)
{
tree body, list;
- const bool check_body_p =
- DECL_CONSTRUCTOR_P (current_function_decl)
- && DECL_DECLARED_CONSTEXPR_P (current_function_decl);
+ const bool check_body_p
+ = (DECL_CONSTRUCTOR_P (current_function_decl)
+ && DECL_DECLARED_CONSTEXPR_P (current_function_decl));
tree last = NULL;
+ if (in_function_try_block
+ && DECL_DECLARED_CONSTEXPR_P (current_function_decl)
+ && cxx_dialect < cxx2a)
+ {
+ if (DECL_CONSTRUCTOR_P (current_function_decl))
+ pedwarn (input_location, 0,
+ "function-try-block body of %<constexpr%> constructor only "
+ "available with %<-std=c++2a%> or %<-std=gnu++2a%>");
+ else
+ pedwarn (input_location, 0,
+ "function-try-block body of %<constexpr%> function only "
+ "available with %<-std=c++2a%> or %<-std=gnu++2a%>");
+ }
+
/* Begin the function body. */
body = begin_function_body ();
/* Parse the optional ctor-initializer. */
/* If it's not a `}', then there is a non-trivial initializer. */
if (cp_lexer_next_token_is_not (parser->lexer, CPP_CLOSE_BRACE))
{
+ bool designated;
/* Parse the initializer list. */
CONSTRUCTOR_ELTS (initializer)
- = cp_parser_initializer_list (parser, non_constant_p);
+ = cp_parser_initializer_list (parser, non_constant_p, &designated);
+ CONSTRUCTOR_IS_DESIGNATED_INIT (initializer) = designated;
/* A trailing `,' token is allowed. */
if (cp_lexer_next_token_is (parser->lexer, CPP_COMMA))
cp_lexer_consume_token (parser->lexer);
Returns a vec of constructor_elt. The VALUE of each elt is an expression
for the initializer. If the INDEX of the elt is non-NULL, it is the
IDENTIFIER_NODE naming the field to initialize. NON_CONSTANT_P is
- as for cp_parser_initializer. */
+ as for cp_parser_initializer. Set *DESIGNATED to a boolean whether there
+ are any designators. */
static vec<constructor_elt, va_gc> *
-cp_parser_initializer_list (cp_parser* parser, bool* non_constant_p)
+cp_parser_initializer_list (cp_parser* parser, bool* non_constant_p,
+ bool *designated)
{
vec<constructor_elt, va_gc> *v = NULL;
bool first_p = true;
if (cxx_dialect < cxx2a)
pedwarn (loc, OPT_Wpedantic,
"C++ designated initializers only available with "
- "-std=c++2a or -std=gnu++2a");
+ "%<-std=c++2a%> or %<-std=gnu++2a%>");
/* Consume the `.'. */
cp_lexer_consume_token (parser->lexer);
/* Consume the identifier. */
IDENTIFIER_MARKED (designator) = 0;
}
+ *designated = first_designator != NULL_TREE;
return v;
}
decl = cp_parser_maybe_treat_template_as_class (decl, class_head_p);
/* If this is a typename, create a TYPENAME_TYPE. */
- if (typename_p && decl != error_mark_node)
+ if (typename_p
+ && decl != error_mark_node
+ && !is_overloaded_fn (decl))
{
decl = make_typename_type (scope, decl, typename_type,
/*complain=*/tf_error);
cp_parser_check_class_key (class_key, type);
/* If this type was already complete, and we see another definition,
- that's an error. */
- if (type != error_mark_node && COMPLETE_TYPE_P (type))
+ that's an error. Likewise if the type is already being defined:
+ this can happen, eg, when it's defined from within an expression
+ (c++/84605). */
+ if (type != error_mark_node
+ && (COMPLETE_TYPE_P (type) || TYPE_BEING_DEFINED (type)))
{
error_at (type_start_token->location, "redefinition of %q#T",
type);
by the standard until C++17. */
pedwarn (token->location, OPT_Wpedantic,
"ISO C++ forbids typename key in template template parameter;"
- " use -std=c++17 or -std=gnu++17");
+ " use %<-std=c++17%> or %<-std=gnu++17%>");
}
else
cp_parser_error (parser, "expected %<class%> or %<typename%>");
&& identifier != NULL_TREE)
pedwarn (loc, 0,
"default member initializers for bit-fields "
- "only available with -std=c++2a or "
- "-std=gnu++2a");
+ "only available with %<-std=c++2a%> or "
+ "%<-std=gnu++2a%>");
initializer = cp_parser_save_nsdmi (parser);
if (identifier == NULL_TREE)
parser->type_definition_forbidden_message
= G_("types may not be defined in an exception-specification");
- expr = cp_parser_constant_expression (parser);
+ bool non_constant_p;
+ expr
+ = cp_parser_constant_expression (parser,
+ /*allow_non_constant=*/true,
+ &non_constant_p);
+ if (non_constant_p
+ && !require_potential_rvalue_constant_expression (expr))
+ {
+ expr = NULL_TREE;
+ return_cond = true;
+ }
/* Restore the saved message. */
parser->type_definition_forbidden_message = saved_message;
cp_parser_require_keyword (parser, RID_TRY, RT_TRY);
if (parser->in_function_body
- && DECL_DECLARED_CONSTEXPR_P (current_function_decl))
- error ("%<try%> in %<constexpr%> function");
+ && DECL_DECLARED_CONSTEXPR_P (current_function_decl)
+ && cxx_dialect < cxx2a)
+ pedwarn (input_location, 0,
+ "%<try%> in %<constexpr%> function only "
+ "available with %<-std=c++2a%> or %<-std=gnu++2a%>");
try_block = begin_try_block ();
cp_parser_compound_statement (parser, NULL, BCS_TRY_BLOCK, false);
cp_lexer_consume_token (parser->lexer);
/* Look for the two `(' tokens. */
matching_parens outer_parens;
- outer_parens.require_open (parser);
+ if (!outer_parens.require_open (parser))
+ ok = false;
matching_parens inner_parens;
- inner_parens.require_open (parser);
+ if (!inner_parens.require_open (parser))
+ ok = false;
/* Peek at the next token. */
token = cp_lexer_peek_token (parser->lexer);
/* A GNU attribute that takes an identifier in parameter. */
attr_flag = id_attr;
+ const attribute_spec *as
+ = lookup_attribute_spec (TREE_PURPOSE (attribute));
+ if (as == NULL)
+ {
+ /* For unknown attributes, just skip balanced tokens instead of
+ trying to parse the arguments. */
+ for (size_t n = cp_parser_skip_balanced_tokens (parser, 1) - 1; n; --n)
+ cp_lexer_consume_token (parser->lexer);
+ return attribute;
+ }
+
vec = cp_parser_parenthesized_expression_list
(parser, attr_flag, /*cast_p=*/false,
/*allow_expansion_p=*/true,
&& !in_system_header_at (input_location))
pedwarn (input_location, 0,
"attribute using prefix only available "
- "with -std=c++17 or -std=gnu++17");
+ "with %<-std=c++17%> or %<-std=gnu++17%>");
cp_lexer_consume_token (parser->lexer);
cp_lexer_consume_token (parser->lexer);
&& tok->u.value == ridpointers[RID_REQUIRES])
{
error_at (cp_lexer_peek_token (parser->lexer)->location,
- "%<requires%> only available with -fconcepts");
+ "%<requires%> only available with %<-fconcepts%>");
/* Parse and discard the requires-clause. */
cp_lexer_consume_token (parser->lexer);
cp_parser_requires_clause (parser);
/* Returns TRUE if the upcoming token sequence is the start of a
constructor declarator or C++17 deduction guide. If FRIEND_P is true, the
- declarator is preceded by the `friend' specifier. */
+ declarator is preceded by the `friend' specifier. The parser flags FLAGS
+ is used to control type-specifier parsing. */
static bool
-cp_parser_constructor_declarator_p (cp_parser *parser, bool friend_p)
+cp_parser_constructor_declarator_p (cp_parser *parser, cp_parser_flags flags,
+ bool friend_p)
{
bool constructor_p;
bool outside_class_specifier_p;
/* A parameter declaration begins with a decl-specifier,
which is either the "attribute" keyword, a storage class
specifier, or (usually) a type-specifier. */
- && !cp_lexer_next_token_is_decl_specifier_keyword (parser->lexer))
+ && (!cp_lexer_next_token_is_decl_specifier_keyword (parser->lexer)
+ /* GNU attributes can actually appear both at the start of
+ a parameter and parenthesized declarator.
+ S (__attribute__((unused)) int);
+ is a constructor, but
+ S (__attribute__((unused)) foo) (int);
+ is a function declaration. */
+ || (cp_parser_allow_gnu_extensions_p (parser)
+ && cp_next_tokens_can_be_gnu_attribute_p (parser)))
+ /* A parameter declaration can also begin with [[attribute]]. */
+ && !cp_next_tokens_can_be_std_attribute_p (parser))
{
tree type;
tree pushed_scope = NULL_TREE;
unsigned saved_num_template_parameter_lists;
+ if (cp_next_tokens_can_be_gnu_attribute_p (parser))
+ {
+ unsigned int n = cp_parser_skip_gnu_attributes_opt (parser, 1);
+ while (--n)
+ cp_lexer_consume_token (parser->lexer);
+ }
+
/* Names appearing in the type-specifier should be looked up
in the scope of the class. */
if (current_class_type)
= parser->num_template_parameter_lists;
parser->num_template_parameter_lists = 0;
- /* Look for the type-specifier. */
+ /* Look for the type-specifier. It's not optional, but its typename
+ might be. Unless this is a friend declaration; we don't want to
+ treat
+
+ friend S (T::fn)(int);
+
+ as a constructor, but with P0634, we might assume a type when
+ looking for the type-specifier. It is actually a function named
+ `T::fn' that takes one parameter (of type `int') and returns a
+ value of type `S'. Constructors can be friends, but they must
+ use a qualified name. */
cp_parser_type_specifier (parser,
- CP_PARSER_FLAGS_NONE,
+ (friend_p ? CP_PARSER_FLAGS_NONE
+ : (flags & ~CP_PARSER_FLAGS_OPTIONAL)),
/*decl_specs=*/NULL,
/*is_declarator=*/true,
/*declares_class_or_enum=*/NULL,
{
tree parm_list = TREE_VEC_ELT (parameter_list, 0);
tree parm = INNERMOST_TEMPLATE_PARMS (parm_list);
- if (CLASS_TYPE_P (TREE_TYPE (parm)))
+ if (TREE_CODE (parm) != PARM_DECL)
+ ok = false;
+ else if (MAYBE_CLASS_TYPE_P (TREE_TYPE (parm))
+ && !TEMPLATE_PARM_PARAMETER_PACK (DECL_INITIAL (parm)))
/* OK, C++20 string literal operator template. We don't need
to warn in lower dialects here because we will have already
warned about the template parameter. */;
tree type = INNERMOST_TEMPLATE_PARMS (parm_type);
tree parm_list = TREE_VEC_ELT (parameter_list, 1);
tree parm = INNERMOST_TEMPLATE_PARMS (parm_list);
- if (parm == error_mark_node
+ if (TREE_CODE (parm) != PARM_DECL
|| TREE_TYPE (parm) != TREE_TYPE (type)
|| !TEMPLATE_PARM_PARAMETER_PACK (DECL_INITIAL (parm)))
ok = false;
if (cxx_dialect > cxx17)
error ("literal operator template %qD has invalid parameter list;"
" Expected non-type template parameter pack <char...> "
- " or single non-type parameter of class type",
+ "or single non-type parameter of class type",
decl);
else
error ("literal operator template %qD has invalid parameter list."
{
tree expr = NULL_TREE;
const char *saved_message;
- char *tmp;
+ const char *saved_message_arg;
bool saved_integral_constant_expression_p;
bool saved_non_integral_constant_expression_p;
/* Types cannot be defined in a `sizeof' expression. Save away the
old message. */
saved_message = parser->type_definition_forbidden_message;
- /* And create the new one. */
- tmp = concat ("types may not be defined in %<",
- IDENTIFIER_POINTER (ridpointers[keyword]),
- "%> expressions", NULL);
- parser->type_definition_forbidden_message = tmp;
+ saved_message_arg = parser->type_definition_forbidden_message_arg;
+ parser->type_definition_forbidden_message
+ = G_("types may not be defined in %qs expressions");
+ parser->type_definition_forbidden_message_arg
+ = IDENTIFIER_POINTER (ridpointers[keyword]);
/* The restrictions on constant-expressions do not apply inside
sizeof expressions. */
--cp_unevaluated_operand;
--c_inhibit_evaluation_warnings;
- /* Free the message we created. */
- free (tmp);
/* And restore the old one. */
parser->type_definition_forbidden_message = saved_message;
+ parser->type_definition_forbidden_message_arg = saved_message_arg;
parser->integral_constant_expression_p
= saved_integral_constant_expression_p;
parser->non_integral_constant_expression_p
decl = TREE_OPERAND (decl, 0);
cp_lexer_consume_token (parser->lexer);
}
+ else if (cp_parser_is_keyword (token, RID_FUNCTION_NAME)
+ || cp_parser_is_keyword (token, RID_PRETTY_FUNCTION_NAME)
+ || cp_parser_is_keyword (token, RID_C99_FUNCTION_NAME))
+ {
+ cp_id_kind idk;
+ decl = cp_parser_primary_expression (parser, false, false, false,
+ &idk);
+ }
else
{
name = cp_parser_id_expression (parser, /*template_p=*/false,
token->location);
}
}
+ if (outer_automatic_var_p (decl))
+ decl = process_outer_var_ref (decl, tf_warning_or_error);
if (decl == error_mark_node)
;
else if (kind != 0)
parser->colon_corrects_to_scope_p = false;
cp_lexer_consume_token (parser->lexer);
if (!cp_lexer_next_token_is (parser->lexer, CPP_COLON))
- low_bound = cp_parser_expression (parser);
+ {
+ low_bound = cp_parser_expression (parser);
+ /* Later handling is not prepared to see through these. */
+ gcc_checking_assert (!location_wrapper_p (low_bound));
+ }
if (!colon)
parser->colon_corrects_to_scope_p
= saved_colon_corrects_to_scope_p;
cp_parser_commit_to_tentative_parse (parser);
if (!cp_lexer_next_token_is (parser->lexer,
CPP_CLOSE_SQUARE))
- length = cp_parser_expression (parser);
+ {
+ length = cp_parser_expression (parser);
+ /* Later handling is not prepared to see through these. */
+ gcc_checking_assert (!location_wrapper_p (length));
+ }
}
/* Look for the closing `]'. */
if (!cp_parser_require (parser, CPP_CLOSE_SQUARE,
seq */
static tree
-cp_parser_oacc_simple_clause (cp_parser * /* parser */,
- enum omp_clause_code code,
- tree list, location_t location)
+cp_parser_oacc_simple_clause (location_t loc, enum omp_clause_code code,
+ tree list)
{
- check_no_duplicate_clause (list, code, omp_clause_code_name[code], location);
- tree c = build_omp_clause (location, code);
+ check_no_duplicate_clause (list, code, omp_clause_code_name[code], loc);
+
+ tree c = build_omp_clause (loc, code);
OMP_CLAUSE_CHAIN (c) = list;
+
return c;
}
*/
static tree
-cp_parser_oacc_shape_clause (cp_parser *parser, omp_clause_code kind,
+cp_parser_oacc_shape_clause (cp_parser *parser, location_t loc,
+ omp_clause_code kind,
const char *str, tree list)
{
const char *id = "num";
cp_lexer *lexer = parser->lexer;
tree ops[2] = { NULL_TREE, NULL_TREE }, c;
- location_t loc = cp_lexer_peek_token (lexer)->location;
if (kind == OMP_CLAUSE_VECTOR)
id = "length";
}
/* OpenACC:
- wait ( int-expr-list ) */
+ wait [( int-expr-list )] */
static tree
cp_parser_oacc_clause_wait (cp_parser *parser, tree list)
{
location_t location = cp_lexer_peek_token (parser->lexer)->location;
- if (cp_lexer_peek_token (parser->lexer)->type != CPP_OPEN_PAREN)
- return list;
+ if (cp_lexer_peek_token (parser->lexer)->type == CPP_OPEN_PAREN)
+ list = cp_parser_oacc_wait_list (parser, location, list);
+ else
+ {
+ tree c = build_omp_clause (location, OMP_CLAUSE_WAIT);
- list = cp_parser_oacc_wait_list (parser, location, list);
+ OMP_CLAUSE_DECL (c) = build_int_cst (integer_type_node, GOMP_ASYNC_NOVAL);
+ OMP_CLAUSE_CHAIN (c) = list;
+ list = c;
+ }
return list;
}
else if (!cp_parser_require (parser, CPP_CLOSE_PAREN, RT_COMMA_CLOSE_PAREN))
goto resync_fail;
- check_no_duplicate_clause (list, OMP_CLAUSE_DIST_SCHEDULE, "dist_schedule",
- location);
+ /* check_no_duplicate_clause (list, OMP_CLAUSE_DIST_SCHEDULE,
+ "dist_schedule", location); */
+ if (omp_find_clause (list, OMP_CLAUSE_DIST_SCHEDULE))
+ warning_at (location, 0, "too many %qs clauses", "dist_schedule");
OMP_CLAUSE_CHAIN (c) = list;
return c;
matching_parens parens;
parens.consume_open (parser);
- t = cp_parser_expression (parser);
+ t = cp_parser_assignment_expression (parser);
if (t == error_mark_node
|| !parens.require_close (parser))
cp_parser_skip_to_closing_parenthesis (parser, /*recovering=*/true,
tree clauses = NULL;
bool first = true;
+ /* Don't create location wrapper nodes within OpenACC clauses. */
+ auto_suppress_location_wrappers sentinel;
+
while (cp_lexer_next_token_is_not (parser->lexer, CPP_PRAGMA_EOL))
{
location_t here;
c_name = "async";
break;
case PRAGMA_OACC_CLAUSE_AUTO:
- clauses = cp_parser_oacc_simple_clause (parser, OMP_CLAUSE_AUTO,
- clauses, here);
+ clauses = cp_parser_oacc_simple_clause (here, OMP_CLAUSE_AUTO,
+ clauses);
c_name = "auto";
break;
case PRAGMA_OACC_CLAUSE_COLLAPSE:
c_name = "device_resident";
break;
case PRAGMA_OACC_CLAUSE_FINALIZE:
- clauses = cp_parser_oacc_simple_clause (parser, OMP_CLAUSE_FINALIZE,
- clauses, here);
+ clauses = cp_parser_oacc_simple_clause (here, OMP_CLAUSE_FINALIZE,
+ clauses);
c_name = "finalize";
break;
case PRAGMA_OACC_CLAUSE_FIRSTPRIVATE:
break;
case PRAGMA_OACC_CLAUSE_GANG:
c_name = "gang";
- clauses = cp_parser_oacc_shape_clause (parser, OMP_CLAUSE_GANG,
+ clauses = cp_parser_oacc_shape_clause (parser, here, OMP_CLAUSE_GANG,
c_name, clauses);
break;
case PRAGMA_OACC_CLAUSE_HOST:
c_name = "if";
break;
case PRAGMA_OACC_CLAUSE_IF_PRESENT:
- clauses = cp_parser_oacc_simple_clause (parser,
- OMP_CLAUSE_IF_PRESENT,
- clauses, here);
+ clauses = cp_parser_oacc_simple_clause (here, OMP_CLAUSE_IF_PRESENT,
+ clauses);
c_name = "if_present";
break;
case PRAGMA_OACC_CLAUSE_INDEPENDENT:
- clauses = cp_parser_oacc_simple_clause (parser,
- OMP_CLAUSE_INDEPENDENT,
- clauses, here);
+ clauses = cp_parser_oacc_simple_clause (here, OMP_CLAUSE_INDEPENDENT,
+ clauses);
c_name = "independent";
break;
case PRAGMA_OACC_CLAUSE_LINK:
c_name = "reduction";
break;
case PRAGMA_OACC_CLAUSE_SEQ:
- clauses = cp_parser_oacc_simple_clause (parser, OMP_CLAUSE_SEQ,
- clauses, here);
+ clauses = cp_parser_oacc_simple_clause (here, OMP_CLAUSE_SEQ,
+ clauses);
c_name = "seq";
break;
case PRAGMA_OACC_CLAUSE_TILE:
break;
case PRAGMA_OACC_CLAUSE_VECTOR:
c_name = "vector";
- clauses = cp_parser_oacc_shape_clause (parser, OMP_CLAUSE_VECTOR,
+ clauses = cp_parser_oacc_shape_clause (parser, here,
+ OMP_CLAUSE_VECTOR,
c_name, clauses);
break;
case PRAGMA_OACC_CLAUSE_VECTOR_LENGTH:
break;
case PRAGMA_OACC_CLAUSE_WORKER:
c_name = "worker";
- clauses = cp_parser_oacc_shape_clause (parser, OMP_CLAUSE_WORKER,
+ clauses = cp_parser_oacc_shape_clause (parser, here,
+ OMP_CLAUSE_WORKER,
c_name, clauses);
break;
default:
cp_parser_end_omp_structured_block (parser, save);
stmt = finish_omp_parallel (cclauses[C_OMP_CLAUSE_SPLIT_PARALLEL],
block);
- OMP_PARALLEL_COMBINED (stmt) = 1;
if (ret == NULL_TREE)
return ret;
+ OMP_PARALLEL_COMBINED (stmt) = 1;
return stmt;
}
else if (!flag_openmp) /* flag_openmp_simd */
static tree
cp_parser_oacc_cache (cp_parser *parser, cp_token *pragma_tok)
{
+ /* Don't create location wrapper nodes within 'OMP_CLAUSE__CACHE_'
+ clauses. */
+ auto_suppress_location_wrappers sentinel;
+
tree stmt, clauses;
clauses = cp_parser_omp_var_list (parser, OMP_CLAUSE__CACHE_, NULL_TREE);
combiner = cp_parser_expression (parser);
finish_expr_stmt (combiner);
block = finish_omp_structured_block (block);
+ if (processing_template_decl)
+ block = build_stmt (input_location, EXPR_STMT, block);
add_stmt (block);
if (!cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN))
block = finish_omp_structured_block (block);
cp_walk_tree (&block, cp_remove_omp_priv_cleanup_stmt, omp_priv, NULL);
+ if (processing_template_decl)
+ block = build_stmt (input_location, EXPR_STMT, block);
add_stmt (block);
if (ctor)
cp_lexer_get_preprocessor_token (NULL, first_token);
if (cp_parser_pragma_kind (first_token) != PRAGMA_GCC_PCH_PREPROCESS)
- return;
+ {
+ c_common_no_more_pch ();
+ return;
+ }
cp_lexer_get_preprocessor_token (NULL, first_token);
if (first_token->type == CPP_STRING)