/* -*- C++ -*- Parser.
- Copyright (C) 2000-2018 Free Software Foundation, Inc.
+ Copyright (C) 2000-2019 Free Software Foundation, Inc.
Written by Mark Mitchell <mark@codesourcery.com>.
This file is part of GCC.
parser->allow_non_integral_constant_expression_p);
cp_debug_print_flag (file, "Seen non-constant expression",
parser->non_integral_constant_expression_p);
- cp_debug_print_flag (file, "Local names and 'this' forbidden in "
- "current context",
- parser->local_variables_forbidden_p);
+ cp_debug_print_flag (file, "Local names forbidden in current context",
+ (parser->local_variables_forbidden_p
+ & LOCAL_VARS_FORBIDDEN));
+ cp_debug_print_flag (file, "'this' forbidden in current context",
+ (parser->local_variables_forbidden_p
+ & THIS_FORBIDDEN));
cp_debug_print_flag (file, "In unbraced linkage specification",
parser->in_unbraced_linkage_specification_p);
cp_debug_print_flag (file, "Parsing a declarator",
case RID_TYPENAME:
/* Simple type specifiers. */
case RID_CHAR:
+ case RID_CHAR8:
case RID_CHAR16:
case RID_CHAR32:
case RID_WCHAR:
/* Search for a declarator name, or any other declarator that goes
after the point where the ellipsis could appear in a parameter
- pack. If we find any of these, then this declarator can not be
+ pack. If we find any of these, then this declarator cannot be
made into a parameter pack. */
bool found = false;
while (declarator && !found)
location_t *, tree *);
static cp_declarator *cp_parser_declarator
(cp_parser *, cp_parser_declarator_kind, cp_parser_flags, int *, bool *,
- bool, bool);
+ bool, bool, bool);
static cp_declarator *cp_parser_direct_declarator
- (cp_parser *, cp_parser_declarator_kind, cp_parser_flags, int *, bool, bool);
+ (cp_parser *, cp_parser_declarator_kind, cp_parser_flags, int *, bool, bool,
+ bool);
static enum tree_code cp_parser_ptr_operator
(cp_parser *, tree *, cp_cv_quals *, tree *);
static cp_cv_quals cp_parser_cv_qualifier_seq_opt
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);
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))
{
parser->non_integral_constant_expression_p = false;
/* Local variable names are not forbidden. */
- parser->local_variables_forbidden_p = false;
+ parser->local_variables_forbidden_p = 0;
/* We are not processing an `extern "C"' declaration. */
parser->in_unbraced_linkage_specification_p = false;
{
default:
case CPP_STRING:
- case CPP_UTF8STRING:
TREE_TYPE (value) = char_array_type_node;
break;
+ case CPP_UTF8STRING:
+ if (flag_char8_t)
+ TREE_TYPE (value) = char8_array_type_node;
+ else
+ TREE_TYPE (value) = char_array_type_node;
+ break;
case CPP_STRING16:
TREE_TYPE (value) = char16_array_type_node;
break;
"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
/* Recognize the `this' keyword. */
case RID_THIS:
cp_lexer_consume_token (parser->lexer);
- if (parser->local_variables_forbidden_p)
+ if (parser->local_variables_forbidden_p & THIS_FORBIDDEN)
{
error_at (token->location,
"%<this%> may not be used in this context");
template <int N> struct A {
int a[B<N>::i];
};
-
+
is accepted. At template-instantiation time, we
will check that B<N>::i is actually a constant. */
return decl;
}
/* Check to see if DECL is a local variable in a context
where that is forbidden. */
- if (parser->local_variables_forbidden_p
+ if ((parser->local_variables_forbidden_p & LOCAL_VARS_FORBIDDEN)
&& local_variable_p (decl))
{
error_at (id_expression.get_location (),
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:
break;
}
+ case RID_BUILTIN_CONVERTVECTOR:
+ {
+ tree expression;
+ tree type;
+ /* Consume the `__builtin_convertvector' token. */
+ cp_lexer_consume_token (parser->lexer);
+ /* Look for the opening `('. */
+ matching_parens parens;
+ parens.require_open (parser);
+ /* Now, parse the assignment-expression. */
+ expression = cp_parser_assignment_expression (parser);
+ /* Look for the `,'. */
+ cp_parser_require (parser, CPP_COMMA, RT_COMMA);
+ location_t type_location
+ = cp_lexer_peek_token (parser->lexer)->location;
+ /* Parse the type-id. */
+ {
+ type_id_in_expr_sentinel s (parser);
+ type = cp_parser_type_id (parser);
+ }
+ /* Look for the closing `)'. */
+ parens.require_close (parser);
+ return cp_build_vec_convert (expression, type_location, type,
+ tf_warning_or_error);
+ }
+
default:
{
tree type;
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;
{
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;
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;
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,
location_t 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");
+ "%<-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 (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);
= 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);
cp_parser_lambda_body (cp_parser* parser, tree lambda_expr)
{
bool nested = (current_function_decl != NULL_TREE);
- bool local_variables_forbidden_p = parser->local_variables_forbidden_p;
+ unsigned char local_variables_forbidden_p
+ = parser->local_variables_forbidden_p;
bool in_function_body = parser->in_function_body;
/* The body of a lambda-expression is not a subexpression of the enclosing
vec<tree> omp_privatization_save;
save_omp_privatization_clauses (omp_privatization_save);
/* Clear this in case we're in the middle of a default argument. */
- parser->local_variables_forbidden_p = false;
+ parser->local_variables_forbidden_p = 0;
parser->in_function_body = true;
{
{
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);
}
/*ctor_dtor_or_conv_p=*/NULL,
/*parenthesized_p=*/NULL,
/*member_p=*/false,
- /*friend_p=*/false);
+ /*friend_p=*/false,
+ /*static_p=*/false);
/* Parse the attributes. */
attributes = cp_parser_attributes_opt (parser);
/* Parse the asm-specification. */
{
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 (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);
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, "");
argument = cp_parser_constant_expression (parser);
else
{
+ /* In C++20, we can encounter a braced-init-list. */
+ if (cxx_dialect >= cxx2a
+ && cp_lexer_next_token_is (parser->lexer, CPP_OPEN_BRACE))
+ {
+ bool expr_non_constant_p;
+ return cp_parser_braced_list (parser, &expr_non_constant_p);
+ }
+
/* With C++17 generalized non-type template arguments we need to handle
lvalue constant expressions, too. */
argument = cp_parser_assignment_expression (parser);
/*ctor_dtor_or_conv_p=*/NULL,
/*parenthesized_p=*/NULL,
/*member_p=*/false,
- /*friend_p=*/false);
+ /*friend_p=*/false,
+ /*static_p=*/false);
if (declares_class_or_enum & 2)
cp_parser_check_for_definition_in_return_type (declarator,
decl_specifiers.type,
decl_specs->explicit_char_p = true;
type = char_type_node;
break;
+ case RID_CHAR8:
+ type = char8_type_node;
+ break;
case RID_CHAR16:
type = char16_type_node;
break;
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 (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))
for (;;)
{
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;
case RID_INLINE:
- if (!parser->in_function_body)
- break;
if (inline_loc)
{
error_at (loc, "duplicate asm qualifier %qT", token->u.value);
}
else
inline_loc = loc;
+ if (!first_loc)
+ first_loc = loc;
cp_lexer_consume_token (parser->lexer);
continue;
case RID_GOTO:
- if (!parser->in_function_body)
- break;
if (goto_loc)
{
error_at (loc, "duplicate asm qualifier %qT", token->u.value);
}
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;
= cp_parser_declarator (parser, CP_PARSER_DECLARATOR_NAMED,
flags, &ctor_dtor_or_conv_p,
/*parenthesized_p=*/NULL,
- member_p, friend_p);
+ member_p, friend_p, /*static_p=*/false);
/* Gather up the deferred checks. */
stop_deferring_access_checks ();
MEMBER_P is true iff this declarator is a member-declarator.
- FRIEND_P is true iff this declarator is a friend. */
+ FRIEND_P is true iff this declarator is a friend.
+
+ STATIC_P is true iff the keyword static was seen. */
static cp_declarator *
cp_parser_declarator (cp_parser* parser,
cp_parser_flags flags,
int* ctor_dtor_or_conv_p,
bool* parenthesized_p,
- bool member_p, bool friend_p)
+ bool member_p, bool friend_p, bool static_p)
{
cp_declarator *declarator;
enum tree_code code;
/*ctor_dtor_or_conv_p=*/NULL,
/*parenthesized_p=*/NULL,
/*member_p=*/false,
- friend_p);
+ friend_p, /*static_p=*/false);
/* If we are parsing an abstract-declarator, we must handle the
case where the dependent declarator is absent. */
CPP_OPEN_PAREN);
declarator = cp_parser_direct_declarator (parser, dcl_kind,
flags, ctor_dtor_or_conv_p,
- member_p, friend_p);
+ member_p, friend_p, static_p);
}
if (gnu_attributes && declarator && declarator != cp_error_declarator)
of ambiguity we prefer an abstract declarator, as per
[dcl.ambig.res].
The parser flags FLAGS is used to control type-specifier parsing.
- CTOR_DTOR_OR_CONV_P, MEMBER_P, and FRIEND_P are
+ CTOR_DTOR_OR_CONV_P, MEMBER_P, FRIEND_P, and STATIC_P are
as for cp_parser_declarator. */
static cp_declarator *
cp_parser_declarator_kind dcl_kind,
cp_parser_flags flags,
int* ctor_dtor_or_conv_p,
- bool member_p, bool friend_p)
+ bool member_p, bool friend_p, bool static_p)
{
cp_token *token;
cp_declarator *declarator = NULL;
tree attrs;
bool memfn = (member_p || (pushed_scope
&& CLASS_TYPE_P (pushed_scope)));
+ unsigned char local_variables_forbidden_p
+ = parser->local_variables_forbidden_p;
+ /* 'this' is not allowed in static member functions. */
+ if (static_p || friend_p)
+ parser->local_variables_forbidden_p |= THIS_FORBIDDEN;
is_declarator = true;
return type, so are not those of the declared
function. */
parser->default_arg_ok_p = false;
+
+ /* Restore the state of local_variables_forbidden_p. */
+ parser->local_variables_forbidden_p
+ = local_variables_forbidden_p;
}
/* Remove the function parms from scope. */
= cp_parser_declarator (parser, dcl_kind, flags,
ctor_dtor_or_conv_p,
/*parenthesized_p=*/NULL,
- member_p, friend_p);
+ member_p, friend_p,
+ /*static_p=*/false);
parser->in_type_id_in_expr_p = saved_in_type_id_in_expr_p;
first = false;
/* Expect a `)'. */
if (pack_expansion_p)
maybe_warn_variadic_templates ();
+
+ /* We're looking for this case in [temp.res]:
+ A qualified-id is assumed to name a type if [...]
+ - it is a decl-specifier of the decl-specifier-seq of a
+ parameter-declaration in a declarator of a function or
+ function template declaration, ... */
+ if (cxx_dialect >= cxx2a
+ && (flags & CP_PARSER_FLAGS_TYPENAME_OPTIONAL)
+ && declarator->kind == cdk_id
+ && !at_class_scope_p ()
+ && cp_lexer_next_token_is (parser->lexer, CPP_OPEN_PAREN))
+ {
+ /* ...whose declarator-id is qualified. If it isn't, never
+ assume the parameters to refer to types. */
+ if (qualifying_scope == NULL_TREE)
+ flags &= ~CP_PARSER_FLAGS_TYPENAME_OPTIONAL;
+ else
+ {
+ /* Now we have something like
+ template <typename T> int C::x(S::p);
+ which can be a function template declaration or a
+ variable template definition. If name lookup for
+ the declarator-id C::x finds one or more function
+ templates, assume S::p to name a type. Otherwise,
+ don't. */
+ tree decl
+ = cp_parser_lookup_name_simple (parser, unqualified_name,
+ token->location);
+ if (!is_overloaded_fn (decl))
+ flags &= ~CP_PARSER_FLAGS_TYPENAME_OPTIONAL;
+ }
+ }
}
handle_declarator:;
CP_PARSER_FLAGS_NONE, NULL,
/*parenthesized_p=*/NULL,
/*member_p=*/false,
- /*friend_p=*/false);
+ /*friend_p=*/false,
+ /*static_p=*/false);
/* Check to see if there really was a declarator. */
if (!cp_parser_parse_definitely (parser))
abstract_declarator = NULL;
/*ctor_dtor_or_conv_p=*/NULL,
parenthesized_p,
/*member_p=*/false,
- /*friend_p=*/false);
+ /*friend_p=*/false,
+ /*static_p=*/false);
parser->default_arg_ok_p = saved_default_arg_ok_p;
/* After the declarator, allow more attributes. */
decl_specifiers.attributes
{
tree default_argument = NULL_TREE;
bool saved_greater_than_is_operator_p;
- bool saved_local_variables_forbidden_p;
+ unsigned char saved_local_variables_forbidden_p;
bool non_constant_p, is_direct_init;
/* Make sure that PARSER->GREATER_THAN_IS_OPERATOR_P is
/* Local variable names (and the `this' keyword) may not
appear in a default argument. */
saved_local_variables_forbidden_p = parser->local_variables_forbidden_p;
- parser->local_variables_forbidden_p = true;
+ parser->local_variables_forbidden_p = LOCAL_VARS_AND_THIS_FORBIDDEN;
/* Parse the assignment-expression. */
if (template_parm_p)
push_deferring_access_checks (dk_no_deferred);
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_ensure_no_oacc_routine (parser);
/* Issue an error message if type-definitions are forbidden here. */
- cp_parser_check_type_definition (parser);
+ bool type_definition_ok_p = cp_parser_check_type_definition (parser);
/* Remember that we are defining one more class. */
++parser->num_classes_being_defined;
/* Inside the class, surrounding template-parameter-lists do not
cp_default_arg_entry *e;
tree save_ccp, save_ccr;
- if (any_erroneous_template_args_p (type))
+ if (!type_definition_ok_p || any_erroneous_template_args_p (type))
{
/* Skip default arguments, NSDMIs, etc, in order to improve
error recovery (c++/71169, c++/71832). */
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)
cp_declarator *declarator;
tree asm_specification;
int ctor_dtor_or_conv_p;
+ bool static_p = (decl_specifiers.storage_class == sc_static);
/* Parse the declarator. */
declarator
&ctor_dtor_or_conv_p,
/*parenthesized_p=*/NULL,
/*member_p=*/true,
- friend_p);
+ friend_p, static_p);
/* If something went wrong parsing the declarator, make sure
that we at least consume some tokens. */
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);
/*ctor_dtor_or_conv_p=*/NULL,
/*parenthesized_p=*/NULL,
/*member_p=*/false,
- /*friend_p=*/false);
+ /*friend_p=*/false,
+ /*static_p=*/false);
/* Restore the saved message. */
parser->type_definition_forbidden_message = saved_message;
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);
&& !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);
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."
static void
cp_parser_late_parsing_default_args (cp_parser *parser, tree fn)
{
- bool saved_local_variables_forbidden_p;
+ unsigned char saved_local_variables_forbidden_p;
tree parm, parmdecl;
/* While we're parsing the default args, we might (due to the
/* Local variable names (and the `this' keyword) may not appear
in a default argument. */
saved_local_variables_forbidden_p = parser->local_variables_forbidden_p;
- parser->local_variables_forbidden_p = true;
+ parser->local_variables_forbidden_p = LOCAL_VARS_AND_THIS_FORBIDDEN;
push_defarg_context (fn);
{
decl_specs->any_specifiers_p = true;
- /* If the user tries to redeclare bool, char16_t, char32_t, or wchar_t
- (with, for example, in "typedef int wchar_t;") we remember that
+ /* If the user tries to redeclare bool, char8_t, char16_t, char32_t, or
+ wchar_t (with, for example, in "typedef int wchar_t;") we remember that
this is what happened. In system headers, we ignore these
declarations so that G++ can work with system headers that are not
C++-safe. */
if (decl_spec_seq_has_spec_p (decl_specs, ds_typedef)
&& !type_definition_p
&& (type_spec == boolean_type_node
+ || type_spec == char8_type_node
|| type_spec == char16_type_node
|| type_spec == char32_type_node
|| type_spec == wchar_type_node)
&ctor_dtor_or_conv_p,
/*parenthesized_p=*/NULL,
/*member_p=*/true,
- /*friend_p=*/false);
+ /*friend_p=*/false,
+ /*static_p=*/false);
peek = cp_lexer_peek_token (parser->lexer);
if (cp_parser_error_occurred (parser))
break;
&ctor_dtor_or_conv_p,
/*parenthesized_p=*/NULL,
/*member_p=*/false,
- /*friend_p=*/false);
+ /*friend_p=*/false,
+ /*static_p=*/false);
}
/* Look for attributes that apply to the ivar. */
/* Parse the declarator. */
declarator = cp_parser_declarator (parser, CP_PARSER_DECLARATOR_NAMED,
CP_PARSER_FLAGS_NONE,
- NULL, NULL, false, false);
+ NULL, NULL, false, false, false);
/* Look for attributes that apply to the ivar. */
attributes = cp_parser_attributes_opt (parser);
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;
}
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:
/*ctor_dtor_or_conv_p=*/NULL,
/*parenthesized_p=*/NULL,
/*member_p=*/false,
- /*friend_p=*/false);
+ /*friend_p=*/false,
+ /*static_p=*/false);
attributes = cp_parser_attributes_opt (parser);
asm_specification = cp_parser_asm_specification_opt (parser);