static cp_token_cache *cp_token_cache_new
(cp_token *, cp_token *);
+static tree cp_parser_late_noexcept_specifier
+ (cp_parser *, tree);
+static void noexcept_override_late_checks
+ (tree, tree);
static void cp_parser_initial_pragma
(cp_token *);
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);
return cp_lexer_token_at (lexer, tp);
}
+/* Overload for make_location, taking the lexer to mean the location of the
+ previous token. */
+
+static inline location_t
+make_location (location_t caret, location_t start, cp_lexer *lexer)
+{
+ cp_token *t = cp_lexer_previous_token (lexer);
+ return make_location (caret, start, t->location);
+}
+
/* nonzero if we are presently saving tokens. */
static inline int
{
/* Warn about the C++0x keyword (but still treat it as
an identifier). */
- warning (OPT_Wc__11_compat,
- "identifier %qE is a keyword in C++11",
- token->u.value);
+ warning_at (token->location, OPT_Wc__11_compat,
+ "identifier %qE is a keyword in C++11",
+ token->u.value);
/* Clear out the C_RID_CODE so we don't warn about this
particular identifier-turned-keyword again. */
C_SET_RID_CODE (token->u.value, RID_MAX);
}
+ if (warn_cxx20_compat
+ && C_RID_CODE (token->u.value) >= RID_FIRST_CXX20
+ && C_RID_CODE (token->u.value) <= RID_LAST_CXX20)
+ {
+ /* Warn about the C++20 keyword (but still treat it as
+ an identifier). */
+ warning_at (token->location, OPT_Wc__20_compat,
+ "identifier %qE is a keyword in C++20",
+ token->u.value);
+
+ /* Clear out the C_RID_CODE so we don't warn about this
+ particular identifier-turned-keyword again. */
+ C_SET_RID_CODE (token->u.value, RID_MAX);
+ }
token->keyword = RID_MAX;
}
case RID_FLOAT:
case RID_DOUBLE:
case RID_VOID:
- /* GNU extensions. */
+ /* GNU extensions. */
case RID_ATTRIBUTE:
case RID_TYPEOF:
/* C++0x extensions. */
case RID_DECLTYPE:
case RID_UNDERLYING_TYPE:
case RID_CONSTEXPR:
+ case RID_CONSTINIT:
return true;
default:
{
if (!LEXER_DEBUGGING_ENABLED_P)
fatal_error (input_location,
- "LEXER_DEBUGGING_ENABLED_P is not set to true");
+ "%<LEXER_DEBUGGING_ENABLED_P%> is not set to true");
lexer->debugging_p = true;
cp_lexer_debug_stream = stderr;
{
if (!LEXER_DEBUGGING_ENABLED_P)
fatal_error (input_location,
- "LEXER_DEBUGGING_ENABLED_P is not set to true");
+ "%<LEXER_DEBUGGING_ENABLED_P%> is not set to true");
lexer->debugging_p = false;
cp_lexer_debug_stream = NULL;
/* Determine whether the declarator we've seen so far can be a
parameter pack, when followed by an ellipsis. */
-static bool
+static bool
declarator_can_be_parameter_pack (cp_declarator *declarator)
{
if (declarator && declarator->parameter_pack_p)
}
return false;
}
-
+
/* The parser. */
/* Overview
/* When parsing a decl-specifier-seq, only allow mutable or constexpr. */
CP_PARSER_FLAGS_ONLY_MUTABLE_OR_CONSTEXPR = 0x10,
/* When parsing a decl-specifier-seq, allow missing typename. */
- CP_PARSER_FLAGS_TYPENAME_OPTIONAL = 0x20
+ CP_PARSER_FLAGS_TYPENAME_OPTIONAL = 0x20,
+ /* When parsing of the noexcept-specifier should be delayed. */
+ CP_PARSER_FLAGS_DELAY_NOEXCEPT = 0x40
};
/* This type is used for parameters and variables which hold
parser->unparsed_queues->last ().nsdmis
#define unparsed_classes \
parser->unparsed_queues->last ().classes
+#define unparsed_noexcepts \
+ parser->unparsed_queues->last ().noexcepts
static void
push_unparsed_function_queues (cp_parser *parser)
{
- cp_unparsed_functions_entry e = {NULL, make_tree_vector (), NULL, NULL};
+ cp_unparsed_functions_entry e = { NULL, make_tree_vector (), NULL, NULL,
+ NULL };
vec_safe_push (parser->unparsed_queues, e);
}
static enum tree_code cp_parser_assignment_operator_opt
(cp_parser *);
static cp_expr cp_parser_expression
- (cp_parser *, cp_id_kind * = NULL, bool = false, bool = false);
+ (cp_parser *, cp_id_kind * = NULL, bool = false, bool = false, bool = false);
static cp_expr cp_parser_constant_expression
(cp_parser *, bool = false, bool * = NULL, bool = false);
static cp_expr cp_parser_builtin_offsetof
(cp_parser *, cp_decl_specifier_seq *, cp_parser_flags);
static tree cp_parser_type_name
(cp_parser *, bool);
-static tree cp_parser_nonclass_name
+static tree cp_parser_nonclass_name
(cp_parser* parser);
static tree cp_parser_elaborated_type_specifier
(cp_parser *, bool, bool);
(cp_parser *, cp_parser_flags);
static cp_parameter_declarator *cp_parser_parameter_declaration
(cp_parser *, cp_parser_flags, bool, bool *);
-static tree cp_parser_default_argument
+static tree cp_parser_default_argument
(cp_parser *, bool);
static void cp_parser_function_body
(cp_parser *, bool);
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 void cp_parser_explicit_specialization
(cp_parser *);
-/* Exception handling [gram.exception] */
+/* Exception handling [gram.except] */
static tree cp_parser_try_block
(cp_parser *);
static tree cp_parser_throw_expression
(cp_parser *);
static tree cp_parser_exception_specification_opt
- (cp_parser *);
+ (cp_parser *, cp_parser_flags);
static tree cp_parser_type_id_list
(cp_parser *);
+static tree cp_parser_noexcept_specification_opt
+ (cp_parser *, cp_parser_flags, bool, bool *, bool);
/* GNU Extensions */
(cp_parser *);
static bool cp_parser_objc_valid_prefix_attributes
(cp_parser *, tree *);
-static void cp_parser_objc_at_property_declaration
+static void cp_parser_objc_at_property_declaration
(cp_parser *) ;
-static void cp_parser_objc_at_synthesize_declaration
+static void cp_parser_objc_at_synthesize_declaration
(cp_parser *) ;
static void cp_parser_objc_at_dynamic_declaration
(cp_parser *) ;
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
break;
default:
gcc_unreachable ();
-
+
}
}
else if (parser->scope == global_namespace)
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;
{
error_at (type_location,
"new types may not be defined in a return type");
- inform (type_location,
+ inform (type_location,
"(perhaps a semicolon is missing after the definition of %qT)",
type);
}
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 (cxx_dialect < cxx2a && id == ridpointers[(int)RID_CONSTINIT])
+ inform (location, "C++20 %<constinit%> only available with "
+ "%<-std=c++2a%> or %<-std=gnu++2a%>");
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))
{
if (TREE_CODE (field) == TYPE_DECL
&& DECL_NAME (field) == id)
{
- inform (location,
+ inform (location,
"(perhaps %<typename %T::%E%> was intended)",
BINFO_TYPE (b), id);
break;
/* Build up a call to the user-defined operator */
/* Lookup the name we got back from the id-expression. */
- vec<tree, va_gc> *args = make_tree_vector ();
+ releasing_vec args;
vec_safe_push (args, value);
decl = lookup_literal_operator (name, args);
if (!decl || decl == error_mark_node)
{
error ("unable to find character literal operator %qD with %qT argument",
name, TREE_TYPE (value));
- release_tree_vector (args);
return error_mark_node;
}
result = finish_call_expr (decl, &args, false, true, tf_warning_or_error);
- release_tree_vector (args);
return result;
}
tree num_string = USERDEF_LITERAL_NUM_STRING (literal);
tree name = cp_literal_operator_id (IDENTIFIER_POINTER (suffix_id));
tree decl, result;
- vec<tree, va_gc> *args;
/* Look for a literal operator taking the exact type of numeric argument
as the literal value. */
- args = make_tree_vector ();
+ releasing_vec args;
vec_safe_push (args, value);
decl = lookup_literal_operator (name, args);
if (decl && decl != error_mark_node)
"floating literal truncated to zero");
}
- release_tree_vector (args);
return result;
}
- release_tree_vector (args);
/* If the numeric argument didn't work, look for a raw literal
operator taking a const char* argument consisting of the number
in string format. */
- args = make_tree_vector ();
+ args->truncate (0);
vec_safe_push (args, num_string);
decl = lookup_literal_operator (name, args);
if (decl && decl != error_mark_node)
{
result = finish_call_expr (decl, &args, false, true,
tf_warning_or_error);
- release_tree_vector (args);
return result;
}
- release_tree_vector (args);
/* If the raw literal didn't work, look for a non-type template
function with parameter pack char.... Call the function with
template parameter characters representing the number. */
- args = make_tree_vector ();
+ args->truncate (0);
decl = lookup_literal_operator (name, args);
if (decl && decl != error_mark_node)
{
decl = lookup_template_function (decl, tmpl_args);
result = finish_call_expr (decl, &args, false, true,
tf_warning_or_error);
- release_tree_vector (args);
return result;
}
- release_tree_vector (args);
-
/* In C++14 the standard library defines complex number suffixes that
conflict with GNU extensions. Prefer them if <complex> is #included. */
bool ext = cpp_get_options (parse_in)->ext_numeric_literals;
else if (i14)
{
inform (token->location, "add %<using namespace std::complex_literals%> "
- "(from <complex>) to enable the C++14 user-defined literal "
+ "(from %<<complex>%>) to enable the C++14 user-defined literal "
"suffixes");
if (ext)
inform (token->location, "or use %<j%> instead of %<i%> for the "
"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)
/* Build up a call to the user-defined operator. */
/* Lookup the name we got back from the id-expression. */
- releasing_vec rargs;
- vec<tree, va_gc> *&args = rargs.get_ref();
+ releasing_vec args;
vec_safe_push (args, value);
vec_safe_push (args, build_int_cst (size_type_node, len));
decl = lookup_literal_operator (name, args);
cp_parser_translation_unit (cp_parser* parser)
{
gcc_checking_assert (!cp_error_declarator);
-
+
/* Create the declarator obstack. */
gcc_obstack_init (&declarator_obstack);
/* Create the error declarator. */
for (;;)
{
cp_token *token = cp_lexer_peek_token (parser->lexer);
-
+
/* If we're entering or exiting a region that's implicitly
extern "C", modify the lang context appropriately. */
if (implicit_extern_c
__builtin_offsetof ( type-id , offsetof-expression )
C++ Extensions:
- __has_nothrow_assign ( type-id )
+ __has_nothrow_assign ( type-id )
__has_nothrow_constructor ( type-id )
__has_nothrow_copy ( type-id )
- __has_trivial_assign ( type-id )
+ __has_trivial_assign ( type-id )
__has_trivial_constructor ( type-id )
__has_trivial_copy ( type-id )
__has_trivial_destructor ( type-id )
- __has_virtual_destructor ( type-id )
+ __has_virtual_destructor ( type-id )
__is_abstract ( type-id )
__is_base_of ( type-id , type-id )
__is_class ( type-id )
&& 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
case RID_HAS_NOTHROW_ASSIGN:
case RID_HAS_NOTHROW_CONSTRUCTOR:
- case RID_HAS_NOTHROW_COPY:
+ case RID_HAS_NOTHROW_COPY:
case RID_HAS_TRIVIAL_ASSIGN:
case RID_HAS_TRIVIAL_CONSTRUCTOR:
- case RID_HAS_TRIVIAL_COPY:
+ case RID_HAS_TRIVIAL_COPY:
case RID_HAS_TRIVIAL_DESTRUCTOR:
case RID_HAS_UNIQUE_OBJ_REPRESENTATIONS:
case RID_HAS_VIRTUAL_DESTRUCTOR:
&& constructor_name_p (token->u.value, scope))))
{
cp_lexer_consume_token (parser->lexer);
- return cp_expr (build_nt (BIT_NOT_EXPR, scope), loc);
+ return build_min_nt_loc (loc, BIT_NOT_EXPR, scope);
}
/* ~auto means the destructor of whatever the object is. */
if (cxx_dialect < cxx14)
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 cp_expr (build_nt (BIT_NOT_EXPR, make_auto (), loc));
+ return build_min_nt_loc (loc, BIT_NOT_EXPR, make_auto ());
}
/* If there was an explicit qualification (S::~T), first look
time. */
type_decl = cp_parser_identifier (parser);
if (type_decl != error_mark_node)
- type_decl = build_nt (BIT_NOT_EXPR, type_decl);
- return cp_expr (type_decl, loc);
+ type_decl = build_min_nt_loc (loc, BIT_NOT_EXPR, type_decl);
+ return type_decl;
}
}
/* If an error occurred, assume that the name of the
class. That allows us to keep parsing after running
into ill-formed destructor names. */
if (type_decl == error_mark_node && scope)
- return build_nt (BIT_NOT_EXPR, scope);
+ return build_min_nt_loc (loc, BIT_NOT_EXPR, scope);
else if (type_decl == error_mark_node)
return error_mark_node;
"typedef-name %qD used as destructor declarator",
type_decl);
- return cp_expr (build_nt (BIT_NOT_EXPR, TREE_TYPE (type_decl), loc));
+ return build_min_nt_loc (loc, BIT_NOT_EXPR, TREE_TYPE (type_decl));
}
case CPP_KEYWORD:
cp_token *token;
/* Remember where the nested-name-specifier starts. */
- if (cp_parser_uncommitted_to_tentative_parse_p (parser))
+ if (cp_parser_uncommitted_to_tentative_parse_p (parser)
+ && cp_lexer_next_token_is_not (parser->lexer, CPP_NESTED_NAME_SPECIFIER))
{
start = cp_lexer_token_position (parser->lexer, false);
push_deferring_access_checks (dk_deferred);
== CPP_SCOPE))
{
token = cp_lexer_consume_token (parser->lexer);
- error_at (token->location, "decltype evaluates to %qT, "
- "which is not a class or enumeration type",
- token->u.tree_check_value->value);
+ tree dtype = token->u.tree_check_value->value;
+ if (dtype != error_mark_node)
+ error_at (token->location, "%<decltype%> evaluates to %qT, "
+ "which is not a class or enumeration type",
+ dtype);
parser->scope = error_mark_node;
error_p = true;
/* As below. */
saved_object_scope = parser->object_scope;
/* Try for a class-name first. If the SAVED_SCOPE is a type, then
there is no need to look for a namespace-name. */
- only_class_p = template_keyword_p
+ only_class_p = template_keyword_p
|| (saved_scope && TYPE_P (saved_scope) && cxx_dialect == cxx98);
if (!only_class_p)
cp_parser_parse_tentatively (parser);
= (cp_parser_skip_to_closing_parenthesis (parser, false, false,
/*consume_paren=*/true)
&& cp_lexer_next_token_is (parser->lexer, CPP_OPEN_BRACE));
-
+
/* Roll back the tokens we skipped. */
cp_lexer_rollback_tokens (parser->lexer);
break;
case RID_REINTCAST:
postfix_expression
- = build_reinterpret_cast (type, expression,
+ = build_reinterpret_cast (type, expression,
tf_warning_or_error);
break;
case RID_CONSTCAST:
index = cp_parser_braced_list (parser, &expr_nonconst_p);
}
else
- index = cp_parser_expression (parser);
+ index = cp_parser_expression (parser, NULL, /*cast_p=*/false,
+ /*decltype_p=*/false,
+ /*warn_comma_p=*/warn_comma_subscript);
}
parser->greater_than_is_operator_p = saved_greater_than_is_operator_p;
(name, parser->scope, scope);
postfix_expression
= finish_class_member_access_expr (postfix_expression, name,
- template_p,
+ template_p,
tf_warning_or_error);
/* Build a location e.g.:
ptr->access_expr
~~~^~~~~~~~~~~~~
where the caret is at the deref token, ranging from
the start of postfix_expression to the end of the access expr. */
- location_t end_loc
- = get_finish (cp_lexer_previous_token (parser->lexer)->location);
location_t combined_loc
- = make_location (input_location, start_loc, end_loc);
+ = make_location (input_location, start_loc, parser->lexer);
protected_set_expr_location (postfix_expression, combined_loc);
}
}
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;
^~~~~~~~~~~~~~
with start == caret at the start of the "alignof"/"sizeof"
token, with the endpoint at the final closing paren. */
- location_t finish_loc
- = cp_lexer_previous_token (parser->lexer)->location;
location_t compound_loc
- = make_location (start_loc, start_loc, finish_loc);
+ = make_location (start_loc, start_loc, parser->lexer);
cp_expr ret_expr (ret);
ret_expr.set_location (compound_loc);
parser->type_definition_forbidden_message = saved_message;
- location_t finish_loc
- = cp_lexer_peek_token (parser->lexer)->location;
parens.require_close (parser);
/* Construct a location of the form:
^~~~~~~~~~~~~~~
with start == caret, finishing at the close-paren. */
location_t noexcept_loc
- = make_location (start_loc, start_loc, finish_loc);
+ = make_location (start_loc, start_loc, parser->lexer);
return cp_expr (finish_noexcept_expr (expr, tf_warning_or_error),
noexcept_loc);
/* Consume the '&&' token. */
cp_lexer_consume_token (parser->lexer);
/* Look for the identifier. */
- location_t finish_loc
- = get_finish (cp_lexer_peek_token (parser->lexer)->location);
identifier = cp_parser_identifier (parser);
/* Construct a location of the form:
&&label
^~~~~~~
with caret==start at the "&&", finish at the end of the label. */
location_t combined_loc
- = make_location (start_loc, start_loc, finish_loc);
+ = make_location (start_loc, start_loc, parser->lexer);
/* Create an expression representing the address. */
expression = finish_label_address_expr (identifier, combined_loc);
if (cp_parser_non_integral_constant_expression (parser,
/* 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
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
with start == caret at the start of the built-in token,
and with the endpoint at the final closing paren. */
- location_t finish_loc
- = cp_lexer_previous_token (parser->lexer)->location;
location_t compound_loc
- = make_location (start_loc, start_loc, finish_loc);
+ = make_location (start_loc, start_loc, parser->lexer);
cp_expr ret_expr (ret ? boolean_true_node : boolean_false_node);
ret_expr.set_location (compound_loc);
{
error_at (token->location,
"array bound forbidden after parenthesized type-id");
- inform (token->location,
+ inform (token->location,
"try removing the parentheses around the type-id");
cp_parser_direct_new_declarator (parser);
}
^~~~~~~~~~~~
with caret == start at the start of the "new" token, and the end
at the end of the final token we consumed. */
- cp_token *end_tok = cp_lexer_previous_token (parser->lexer);
- location_t end_loc = get_finish (end_tok->location);
- location_t combined_loc = make_location (start_loc, start_loc, end_loc);
+ location_t combined_loc = make_location (start_loc, start_loc,
+ parser->lexer);
/* Create a representation of the new-expression. */
ret = build_new (&placement, type, nelts, &initializer, global_scope_p,
{
enum tree_code code;
tree type, std_attributes = NULL_TREE;
- cp_cv_quals cv_quals;
+ cp_cv_quals cv_quals;
/* We don't know if there's a ptr-operator next, or not. */
cp_parser_parse_tentatively (parser);
return expr;
}
}
- else
+ else
cp_parser_abort_tentative_parse (parser);
}
{
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
if (cp_parser_allow_gnu_extensions_p (parser)
&& token->type == CPP_COLON)
{
- pedwarn (token->location, OPT_Wpedantic,
- "ISO C++ does not allow ?: with omitted middle operand");
+ pedwarn (token->location, OPT_Wpedantic,
+ "ISO C++ does not allow %<?:%> with omitted middle operand");
/* Implicit true clause. */
expr = NULL_TREE;
c_inhibit_evaluation_warnings +=
CAST_P is true if this expression is the target of a cast.
DECLTYPE_P is true if this expression is the immediate operand of decltype,
except possibly parenthesized or on the RHS of a comma (N3276).
+ WARN_COMMA_P is true if a comma should be diagnosed.
Returns a representation of the expression. */
static cp_expr
cp_parser_expression (cp_parser* parser, cp_id_kind * pidk,
- bool cast_p, bool decltype_p)
+ bool cast_p, bool decltype_p, bool warn_comma_p)
{
cp_expr expression = NULL_TREE;
location_t loc = UNKNOWN_LOCATION;
break;
/* Consume the `,'. */
loc = cp_lexer_peek_token (parser->lexer)->location;
+ if (warn_comma_p)
+ {
+ /* [depr.comma.subscript]: A comma expression appearing as
+ the expr-or-braced-init-list of a subscripting expression
+ is deprecated. A parenthesized comma expression is not
+ deprecated. */
+ warning_at (loc, OPT_Wcomma_subscript,
+ "top-level comma expression in array subscript "
+ "is deprecated");
+ warn_comma_p = false;
+ }
cp_lexer_consume_token (parser->lexer);
/* A comma operator cannot appear in a constant-expression. */
if (cp_parser_non_integral_constant_expression (parser, NIC_COMMA))
{
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;
}
if (binary)
{
cp_parser_require (parser, CPP_COMMA, RT_COMMA);
-
+
{
type_id_in_expr_sentinel s (parser);
type2 = cp_parser_type_id (parser);
case CPTK_DIRECT_BASES:
return cp_expr (finish_bases (type1, true), trait_loc);
default:
- return cp_expr (finish_trait_expr (kind, type1, type2), trait_loc);
+ return finish_trait_expr (trait_loc, kind, type1, type2);
}
}
{
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;
if (ok)
maybe_add_lambda_conv_op (type);
- type = finish_struct (type, /*attributes=*/NULL_TREE);
+ finish_struct (type, /*attributes=*/NULL_TREE);
parser->num_template_parameter_lists = saved_num_template_parameter_lists;
parser->in_statement = in_statement;
insert_pending_capture_proxies ();
/* Update the lambda expression to a range. */
- cp_token *end_tok = cp_lexer_previous_token (parser->lexer);
LAMBDA_EXPR_LOCATION (lambda_expr) = make_location (token->location,
token->location,
- end_tok->location);
+ parser->lexer);
if (ok)
lambda_expr = build_lambda_object (lambda_expr);
/* Record default capture mode. "[&" "[=" "[&," "[=," */
if (cp_lexer_next_token_is (parser->lexer, CPP_AND)
- && cp_lexer_peek_nth_token (parser->lexer, 2)->type != CPP_NAME)
+ && !cp_lexer_nth_token_is (parser->lexer, 2, CPP_NAME)
+ && !cp_lexer_nth_token_is_keyword (parser->lexer, 2, RID_THIS))
LAMBDA_EXPR_DEFAULT_CAPTURE_MODE (lambda_expr) = CPLD_REFERENCE;
else if (cp_lexer_next_token_is (parser->lexer, CPP_EQ))
LAMBDA_EXPR_DEFAULT_CAPTURE_MODE (lambda_expr) = CPLD_COPY;
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);
+ 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;
+ }
+
+ /* But reject `&this'. */
+ if (cp_lexer_next_token_is (parser->lexer, CPP_AND)
+ && cp_lexer_nth_token_is_keyword (parser->lexer, 2, RID_THIS))
+ {
+ error_at (cp_lexer_peek_token (parser->lexer)->location,
+ "%<this%> cannot be captured by reference");
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);
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.is_empty ())
+ 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);
/* 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);
tx_qual = cp_parser_tx_qualifier_opt (parser);
/* Parse optional exception specification. */
- exception_spec = cp_parser_exception_specification_opt (parser);
+ exception_spec
+ = cp_parser_exception_specification_opt (parser, CP_PARSER_FLAGS_NONE);
- attributes = cp_parser_std_attribute_spec_seq (parser);
+ 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);
}
+ if (cp_next_tokens_can_be_gnu_attribute_p (parser))
+ 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);
+ gnu_attrs);
if (fco != error_mark_node)
{
DECL_INITIALIZED_IN_CLASS_P (fco) = 1;
DECL_ARTIFICIAL (fco) = 1;
/* Give the object parameter a different name. */
DECL_NAME (DECL_ARGUMENTS (fco)) = closure_identifier;
- DECL_LAMBDA_FUNCTION (fco) = 1;
+ DECL_SET_LAMBDA_FUNCTION (fco, true);
}
if (template_param_list)
{
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);
- }
+ attrs_loc = make_location (attrs_loc, attrs_loc, parser->lexer);
if (c_dialect_objc ())
{
if (!cp_parser_parse_definitely (parser))
}
cp_parser_declaration_statement (parser);
return;
-
+
case RID_TRANSACTION_ATOMIC:
case RID_TRANSACTION_RELAXED:
case RID_SYNCHRONIZED:
|| token->type == CPP_PRAGMA_EOL
|| (token->type == CPP_KEYWORD && token->keyword == RID_AT_END))
break;
-
+
/* If we are in a compound statement and find 'else' then
something went wrong. */
else if (token->type == CPP_KEYWORD && token->keyword == RID_ELSE)
{
- if (parser->in_statement & IN_IF_STMT)
+ if (parser->in_statement & IN_IF_STMT)
break;
else
{
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);
}
/* Restore the saved message. */
parser->type_definition_forbidden_message = saved_message;
+ /* Gather the attributes that were provided with the
+ decl-specifiers. */
+ tree prefix_attributes = type_specifiers.attributes;
+
cp_parser_maybe_commit_to_declaration (parser,
type_specifiers.any_specifiers_p);
if (cp_lexer_next_token_is_not (parser->lexer, CPP_EQ)
&& cp_lexer_next_token_is_not (parser->lexer, CPP_OPEN_BRACE))
cp_parser_simulate_error (parser);
-
+
/* If we did see an `=' or '{', then we are looking at a declaration
for sure. */
if (cp_parser_parse_definitely (parser))
/* Create the declaration. */
decl = start_decl (declarator, &type_specifiers,
/*initialized_p=*/true,
- attributes, /*prefix_attributes=*/NULL_TREE,
+ attributes, prefix_attributes,
&pushed_scope);
/* Parse the initializer. */
else
{
/* Use global functions with ADL. */
- vec<tree, va_gc> *vec;
- vec = make_tree_vector ();
+ releasing_vec vec;
vec_safe_push (vec, range);
tf_warning_or_error);
*end = finish_call_expr (member_end, &vec, false, true,
tf_warning_or_error);
-
- release_tree_vector (vec);
}
/* Last common checks. */
cp_parser_range_for_member_function (tree range, tree identifier)
{
tree member, res;
- vec<tree, va_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 ();
+ releasing_vec vec;
res = finish_call_expr (member, &vec,
/*disallow_virtual=*/false,
/*koenig_p=*/false,
tf_warning_or_error);
- release_tree_vector (vec);
return res;
}
{
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
switch (keyword)
{
case RID_BREAK:
- in_statement = parser->in_statement & ~IN_IF_STMT;
+ in_statement = parser->in_statement & ~IN_IF_STMT;
switch (in_statement)
{
case 0:
expression. */
expr = NULL_TREE;
/* Build the return-statement. */
- if (current_function_auto_return_pattern && in_discarded_stmt)
+ if (FNDECL_USED_AUTO (current_function_decl) && in_discarded_stmt)
/* Don't deduce from a discarded return statement. */;
else
statement = finish_return_stmt (expr);
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 (decl != error_mark_node)
{
+ int flags = (decl_spec_seq_has_spec_p (decl_specifiers, ds_constinit)
+ ? LOOKUP_CONSTINIT : 0);
cp_maybe_mangle_decomp (decl, prev, v.length ());
cp_finish_decl (decl, initializer, non_constant_p, NULL_TREE,
- is_direct_init ? LOOKUP_NORMAL : LOOKUP_IMPLICIT);
+ (is_direct_init ? LOOKUP_NORMAL : LOOKUP_IMPLICIT)
+ | flags);
cp_finish_decomp (decl, prev, v.length ());
}
}
{
/* decl-specifier:
friend
- constexpr */
+ constexpr
+ constinit */
case RID_FRIEND:
if (!at_class_scope_p ())
{
cp_lexer_consume_token (parser->lexer);
break;
+ case RID_CONSTINIT:
+ ds = ds_constinit;
+ cp_lexer_consume_token (parser->lexer);
+ break;
+
case RID_CONCEPT:
ds = ds_concept;
cp_lexer_consume_token (parser->lexer);
+ /* 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:
GNU Extension:
thread */
case RID_AUTO:
- if (cxx_dialect == cxx98)
+ if (cxx_dialect == cxx98)
{
/* Consume the token. */
cp_lexer_consume_token (parser->lexer);
if (found_decl_spec
&& (flags & CP_PARSER_FLAGS_ONLY_TYPE_OR_CONSTEXPR)
&& token->keyword != RID_CONSTEXPR)
- error ("decl-specifier invalid in condition");
+ error ("%<decl-specifier%> invalid in condition");
if (found_decl_spec
&& (flags & CP_PARSER_FLAGS_ONLY_MUTABLE_OR_CONSTEXPR)
= (!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. */
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);
/* Parse a static_assert-declaration.
static_assert-declaration:
- static_assert ( constant-expression , string-literal ) ;
+ static_assert ( constant-expression , string-literal ) ;
static_assert ( constant-expression ) ; (C++17)
If MEMBER_P, this static_assert is a class member. */
-static void
+static void
cp_parser_static_assert(cp_parser *parser, bool member_p)
{
cp_expr condition;
token_loc = cp_lexer_peek_token (parser->lexer)->location;
/* Look for the `static_assert' keyword. */
- if (!cp_parser_require_keyword (parser, RID_STATIC_ASSERT,
+ if (!cp_parser_require_keyword (parser, RID_STATIC_ASSERT,
RT_STATIC_ASSERT))
return;
/* Parse the constant-expression. Allow a non-constant expression
here in order to give better diagnostics in finish_static_assert. */
- condition =
+ condition =
cp_parser_constant_expression (parser,
/*allow_non_constant_p=*/true,
/*non_constant_p=*/&dummy);
{
if (cxx_dialect < cxx17)
pedwarn (input_location, OPT_Wpedantic,
- "static_assert without a message "
- "only available with -std=c++17 or -std=gnu++17");
+ "%<static_assert%> without a message "
+ "only available with %<-std=c++17%> or %<-std=gnu++17%>");
/* Eat the ')' */
cp_lexer_consume_token (parser->lexer);
message = build_string (1, "");
cp_parser_require (parser, CPP_COMMA, RT_COMMA);
/* Parse the string-literal message. */
- message = cp_parser_string_literal (parser,
+ message = cp_parser_string_literal (parser,
/*translate=*/false,
/*wide_ok=*/true);
/* A `)' completes the static assertion. */
if (!parens.require_close (parser))
- cp_parser_skip_to_closing_parenthesis (parser,
- /*recovering=*/true,
+ cp_parser_skip_to_closing_parenthesis (parser,
+ /*recovering=*/true,
/*or_comma=*/false,
/*consume_paren=*/true);
}
if (assert_loc == UNKNOWN_LOCATION)
assert_loc = token_loc;
- /* Complete the static assertion, which may mean either processing
+ /* Complete the static assertion, which may mean either processing
the static assert now or saving it for template instantiation. */
finish_static_assert (condition, message, assert_loc, member_p);
}
id_expression_or_member_access_p = true;
}
- if (expr
+ if (expr
&& expr != error_mark_node
&& cp_lexer_peek_token (parser->lexer)->type == CPP_CLOSE_PAREN)
/* We have an id-expression. */
/*cast_p=*/false, /*decltype*/true,
/*member_access_only_p=*/true, NULL);
- if (expr
+ if (expr
&& expr != error_mark_node
&& cp_lexer_peek_token (parser->lexer)->type == CPP_CLOSE_PAREN)
/* We have an id-expression. */
push_deferring_access_checks (dk_deferred);
tree expr = NULL_TREE;
-
+
if (cxx_dialect >= cxx14
&& cp_lexer_next_token_is_keyword (parser->lexer, RID_AUTO))
/* decltype (auto) */
cp_lexer_purge_tokens_after (parser->lexer, start_token);
pop_to_parent_deferring_access_checks ();
-
+
return expr;
}
parser->type_definition_forbidden_message
= G_("types may not be defined in a conversion-type-id");
- /* Parse the type-specifiers. */
- cp_parser_type_specifier_seq (parser, CP_PARSER_FLAGS_NONE,
+ /* Parse the type-specifiers. DR 2413 clarifies that `typename' is
+ optional in conversion-type-id. */
+ cp_parser_type_specifier_seq (parser, CP_PARSER_FLAGS_TYPENAME_OPTIONAL,
/*is_declaration=*/false,
/*is_trailing_return=*/false,
&type_specifiers);
/* `typename' is not allowed in this context ([temp.res]). */
if (cp_lexer_next_token_is_keyword (parser->lexer, RID_TYPENAME))
{
- error_at (token->location,
+ error_at (token->location,
"keyword %<typename%> not allowed in this context (a qualified "
"member initializer is implicitly a type)");
cp_lexer_consume_token (parser->lexer);
^~~~~~~~~~~~~~~~~~~~~
with caret == start at the start token, finish at the end of the
suffix identifier. */
- location_t finish_loc
- = get_finish (cp_lexer_previous_token (parser->lexer)->location);
location_t combined_loc
- = make_location (start_loc, start_loc, finish_loc);
+ = make_location (start_loc, start_loc, parser->lexer);
return cp_expr (id, combined_loc);
}
/* Parse the template-parameter. */
parm_loc = cp_lexer_peek_token (parser->lexer)->location;
- parameter = cp_parser_template_parameter (parser,
+ parameter = cp_parser_template_parameter (parser,
&is_non_type,
&is_parameter_pack);
/* Add it to the list. */
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
with caret == start at the start of the template-name,
ranging until the closing '>'. */
- location_t finish_loc
- = get_finish (cp_lexer_previous_token (parser->lexer)->location);
location_t combined_loc
- = make_location (token->location, token->location, finish_loc);
+ = make_location (token->location, token->location, parser->lexer);
/* Check for concepts autos where they don't belong. We could
identify types in some cases of idnetifier TEMPL, looking ahead
{
/* If it's not a class-template or a template-template, it should be
a function-template. */
- gcc_assert ((DECL_FUNCTION_TEMPLATE_P (templ)
- || TREE_CODE (templ) == OVERLOAD
- || TREE_CODE (templ) == FUNCTION_DECL
- || BASELINK_P (templ)));
+ gcc_assert (OVL_P (templ) || BASELINK_P (templ));
template_id = lookup_template_function (templ, arguments);
if (TREE_CODE (template_id) == TEMPLATE_ID_EXPR)
Here 'X()' is a valid type-id of a function type, but the user just
wanted to write the expression "X() >> 5". Thus, we remember that we
found a valid type-id, but we still try to parse the argument as an
- expression to see what happens.
+ expression to see what happens.
In C++0x, the '>>' will be considered two separate '>'
tokens. */
simple-type-specifier:
auto
- decltype ( expression )
+ decltype ( expression )
char16_t
char32_t
__underlying_type ( type-id )
{
decl_specs->explicit_intN_p = true;
decl_specs->int_n_idx = idx;
+ /* Check if the alternate "__intN__" form has been used instead of
+ "__intN". */
+ if (strncmp (IDENTIFIER_POINTER (token->u.value)
+ + (IDENTIFIER_LENGTH (token->u.value) - 2),
+ "__", 2) == 0)
+ decl_specs->int_n_alt = true;
}
type = int_n_trees [idx].signed_type;
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 ();
/* Don't gobble tokens or issue error messages if this is an
optional type-specifier. */
- if ((flags & CP_PARSER_FLAGS_OPTIONAL) || cxx_dialect >= cxx17)
+ if (flags & CP_PARSER_FLAGS_OPTIONAL)
cp_parser_parse_tentatively (parser);
token = cp_lexer_peek_token (parser->lexer);
else
{
cp_parser_error (parser, "expected template-id for type");
- type = NULL_TREE;
+ type = error_mark_node;
}
}
}
- /* Otherwise, look for a type-name. */
- else
- type = cp_parser_type_name (parser, (qualified_p && typename_p));
- /* Keep track of all name-lookups performed in class scopes. */
- if (type
- && !global_p
- && !qualified_p
- && TREE_CODE (type) == TYPE_DECL
- && identifier_p (DECL_NAME (type)))
- maybe_note_name_used_in_class (DECL_NAME (type), type);
- /* If it didn't work out, we don't have a TYPE. */
- if (((flags & CP_PARSER_FLAGS_OPTIONAL) || cxx_dialect >= cxx17)
- && !cp_parser_parse_definitely (parser))
- type = NULL_TREE;
- if (!type && cxx_dialect >= cxx17)
+ /* Otherwise, look for a type-name. */
+ if (!type)
{
- if (flags & CP_PARSER_FLAGS_OPTIONAL)
+ if (cxx_dialect >= cxx17)
cp_parser_parse_tentatively (parser);
- cp_parser_global_scope_opt (parser,
- /*current_scope_valid_p=*/false);
- cp_parser_nested_name_specifier_opt (parser,
- /*typename_keyword_p=*/false,
- /*check_dependency_p=*/true,
- /*type_p=*/false,
- /*is_declaration=*/false);
+ type = cp_parser_type_name (parser, (qualified_p && typename_p));
+
+ if (cxx_dialect >= cxx17 && !cp_parser_parse_definitely (parser))
+ type = NULL_TREE;
+ }
+
+ if (!type && cxx_dialect >= cxx17)
+ {
+ /* Try class template argument deduction. */
tree name = cp_parser_identifier (parser);
if (name && TREE_CODE (name) == IDENTIFIER_NODE
&& parser->scope != error_mark_node)
}
else
type = error_mark_node;
-
- if ((flags & CP_PARSER_FLAGS_OPTIONAL)
- && !cp_parser_parse_definitely (parser))
- type = NULL_TREE;
}
+
+ /* If it didn't work out, we don't have a TYPE. */
+ if ((flags & CP_PARSER_FLAGS_OPTIONAL)
+ && !cp_parser_parse_definitely (parser))
+ type = NULL_TREE;
+
+ /* Keep track of all name-lookups performed in class scopes. */
+ if (type
+ && !global_p
+ && !qualified_p
+ && TREE_CODE (type) == TYPE_DECL
+ && identifier_p (DECL_NAME (type)))
+ maybe_note_name_used_in_class (DECL_NAME (type), type);
+
if (type && decl_specs)
cp_parser_set_decl_spec_type (decl_specs, type,
token,
/*is_declaration=*/false);
/* Note that this must be an instantiation of an alias template
because [temp.names]/6 says:
-
+
A template-id that names an alias template specialization
is a type-name.
Whereas [temp.names]/7 says:
-
+
A simple-template-id that names a class template
specialization is a class-name.
type_decl = cp_parser_lookup_name_simple (parser, identifier, token->location);
type_decl = strip_using_decl (type_decl);
-
+
/* If we found an overload set, then it may refer to a concept-name. */
if (tree decl = cp_parser_maybe_concept_name (parser, type_decl))
type_decl = decl;
else if (type_decl != error_mark_node
&& !parser->scope)
maybe_note_name_used_in_class (identifier, type_decl);
-
+
return type_decl;
}
/* If the `typename' keyword is in effect and DECL is not a type
decl, then type is non existent. */
else if (tag_type == typename_type && TREE_CODE (decl) != TYPE_DECL)
- ;
+ ;
else if (TREE_CODE (decl) == TYPE_DECL)
{
type = check_elaborated_type_specifier (tag_type, decl,
check_unqualified_spec_or_inst (type, token->location);
}
else if (decl == error_mark_node)
- type = error_mark_node;
+ type = error_mark_node;
}
if (!type)
enum-key identifier enum-base [opt] ;
GNU Extensions:
- enum-key attributes[opt] identifier [opt] enum-base [opt]
+ enum-key attributes[opt] identifier [opt] enum-base [opt]
{ enumerator-list [opt] }attributes[opt]
enum-key attributes[opt] identifier [opt] enum-base [opt]
{ enumerator-list, }attributes[opt] [C++0x]
for (;;)
{
identifier = NULL_TREE;
-
+
bool nested_inline_p = cp_lexer_next_token_is_keyword (parser->lexer,
RID_INLINE);
if (nested_inline_p && nested_definition_count != 0)
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);
}
is_inline |= nested_inline_p;
break;
}
-
+
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). */
if (nested_definition_count && !identifier)
cp_parser_error (parser, "namespace name required");
-
+
if (nested_definition_count && attribs)
error_at (token->location,
"a nested namespace definition cannot have attributes");
return;
/* Look for the `=' token. */
if (!cp_parser_uncommitted_to_tentative_parse_p (parser)
- && cp_lexer_next_token_is (parser->lexer, CPP_OPEN_BRACE))
+ && cp_lexer_next_token_is (parser->lexer, CPP_OPEN_BRACE))
{
error_at (token->location, "%<namespace%> definition is not allowed here");
/* Skip the definition. */
/* Look for the qualified-namespace-specifier. */
namespace_specifier
= cp_parser_qualified_namespace_specifier (parser);
+ cp_warn_deprecated_use_scopes (namespace_specifier);
/* Look for the `;' token. */
cp_parser_require (parser, CPP_SEMICOLON, RT_SEMICOLON);
using-declaration:
using typename [opt] :: [opt] nested-name-specifier unqualified-id ;
- using :: unqualified-id ;
+ using :: unqualified-id ;
access-declaration:
- qualified-id ;
+ qualified-id ;
*/
static bool
-cp_parser_using_declaration (cp_parser* parser,
+cp_parser_using_declaration (cp_parser* parser,
bool access_declaration_p)
{
cp_token *token;
{
/* Look for the `using' keyword. */
cp_parser_require_keyword (parser, RID_USING, RT_USING);
-
+
again:
/* Peek at the next token. */
token = cp_lexer_peek_token (parser->lexer);
&& !TYPE_FUNCTION_SCOPE_P (qscope))
qscope = CP_TYPE_CONTEXT (qscope);
+ cp_warn_deprecated_use_scopes (qscope);
+
if (access_declaration_p && cp_parser_error_occurred (parser))
/* Something has already gone wrong; there's no need to parse
further. Since an error has occurred, the return value of
&& !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);
}
finish_member_declaration (decl);
}
else
- {
- decl = cp_parser_lookup_name_simple (parser,
- identifier,
- token->location);
- if (decl == error_mark_node)
- cp_parser_name_lookup_error (parser, identifier,
- decl, NLE_NULL,
- token->location);
- else if (check_for_bare_parameter_packs (decl))
- {
- cp_parser_require (parser, CPP_SEMICOLON, RT_SEMICOLON);
- return false;
- }
- else if (!at_namespace_scope_p ())
- finish_local_using_decl (decl, qscope, identifier);
- else
- finish_namespace_using_decl (decl, qscope, identifier);
- }
+ finish_nonmember_using_decl (qscope, identifier);
}
if (!access_declaration_p
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;
}
if (decl == error_mark_node)
return decl;
- // Attach constraints to the alias declaration.
+ /* Attach constraints to the alias declaration. */
if (flag_concepts && current_template_parms)
{
tree reqs = TEMPLATE_PARMS_CONSTRAINTS (current_template_parms);
/*is_declaration=*/true);
/* Get the namespace being used. */
namespace_decl = cp_parser_namespace_name (parser);
+ cp_warn_deprecated_use_scopes (namespace_decl);
/* And any specified attributes. */
attribs = cp_parser_attributes_opt (parser);
/* Update the symbol table. */
- if (namespace_bindings_p ())
- finish_namespace_using_directive (namespace_decl, attribs);
- else
- finish_local_using_directive (namespace_decl, attribs);
+ finish_using_directive (namespace_decl, attribs);
/* Look for the final `;'. */
cp_parser_require (parser, CPP_SEMICOLON, RT_SEMICOLON);
bool invalid_inputs_p = false;
bool invalid_outputs_p = false;
required_token missing = RT_NONE;
+ location_t asm_loc = cp_lexer_peek_token (parser->lexer)->location;
/* Look for the `asm' keyword. */
cp_parser_require_keyword (parser, RID_ASM, RT_ASM);
+ /* In C++2a, unevaluated inline assembly is permitted in constexpr
+ functions. */
if (parser->in_function_body
- && DECL_DECLARED_CONSTEXPR_P (current_function_decl))
- {
- error ("%<asm%> in %<constexpr%> function");
- cp_function_chain->invalid_constexpr = true;
- }
+ && DECL_DECLARED_CONSTEXPR_P (current_function_decl)
+ && (cxx_dialect < cxx2a))
+ pedwarn (asm_loc, 0, "%<asm%> in %<constexpr%> function only available "
+ "with %<-std=c++2a%> or %<-std=gnu++2a%>");
/* Handle the asm-qualifier-list. */
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);
case RID_VOLATILE:
if (volatile_loc)
{
- error_at (loc, "duplicate asm qualifier %qT", token->u.value);
+ error_at (loc, "duplicate %<asm%> qualifier %qT",
+ token->u.value);
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 (inline_loc)
{
- error_at (loc, "duplicate asm qualifier %qT", token->u.value);
+ error_at (loc, "duplicate %<asm%> qualifier %qT",
+ token->u.value);
inform (inline_loc, "first seen here");
}
else
inline_loc = loc;
+ if (!first_loc)
+ first_loc = loc;
cp_lexer_consume_token (parser->lexer);
continue;
case RID_GOTO:
if (goto_loc)
{
- error_at (loc, "duplicate asm qualifier %qT", token->u.value);
+ error_at (loc, "duplicate %<asm%> qualifier %qT",
+ token->u.value);
inform (goto_loc, "first seen here");
}
else
goto_loc = loc;
+ if (!first_loc)
+ first_loc = loc;
cp_lexer_consume_token (parser->lexer);
continue;
case RID_CONST:
case RID_RESTRICT:
- error_at (loc, "%qT is not an asm qualifier", token->u.value);
+ error_at (loc, "%qT is not an %<asm%> qualifier", token->u.value);
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;
/* Create the ASM_EXPR. */
if (parser->in_function_body)
{
- asm_stmt = finish_asm_stmt (volatile_p, string, outputs,
+ asm_stmt = finish_asm_stmt (asm_loc, volatile_p, string, outputs,
inputs, clobbers, labels, inline_p);
/* If the extended syntax was not used, mark the ASM_EXPR. */
if (!extended_p)
on a function-definition. */
if (asm_specification)
error_at (asm_spec_start_token->location,
- "an asm-specification is not allowed "
+ "an %<asm%> specification is not allowed "
"on a function-definition");
if (attributes)
error_at (attributes_start_token->location,
declarations. */
if (!member_p && decl && decl != error_mark_node && !range_for_decl_p)
{
+ int cf = (decl_spec_seq_has_spec_p (decl_specifiers, ds_constinit)
+ ? LOOKUP_CONSTINIT : 0);
cp_finish_decl (decl,
initializer, !is_non_constant_init,
asm_specification,
`explicit' constructor is OK. Otherwise, an
`explicit' constructor cannot be used. */
((is_direct_init || !is_initialized)
- ? LOOKUP_NORMAL : LOOKUP_IMPLICIT));
+ ? LOOKUP_NORMAL : LOOKUP_IMPLICIT) | cf);
}
else if ((cxx_dialect != cxx98) && friend_p
&& decl && TREE_CODE (decl) == FUNCTION_DECL)
/* Core issue #226 (C++0x only): A default template-argument
shall not be specified in a friend class template
declaration. */
- check_default_tmpl_args (decl, current_template_parms, /*is_primary=*/true,
+ check_default_tmpl_args (decl, current_template_parms, /*is_primary=*/true,
/*is_partial=*/false, /*is_friend_decl=*/1);
if (!friend_p && pushed_scope)
tree tx_qual = cp_parser_tx_qualifier_opt (parser);
/* And the exception-specification. */
exception_specification
- = cp_parser_exception_specification_opt (parser);
+ = cp_parser_exception_specification_opt (parser, flags);
attrs = cp_parser_std_attribute_spec_seq (parser);
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;
}
}
return error_mark_node;
}
}
-
+
return groktypename (&type_specifier_seq, abstract_declarator,
is_template_arg);
}
/* Consume the `...'. */
cp_lexer_consume_token (parser->lexer);
maybe_warn_variadic_templates ();
-
+
/* Build a pack expansion type */
if (template_parm_p)
template_parameter_pack_p = true;
&& !LAMBDA_TYPE_P (current_class_type))
default_argument = cp_parser_cache_defarg (parser, /*nsdmi=*/false);
- // A constrained-type-specifier may declare a type template-parameter.
+ /* A constrained-type-specifier may declare a type
+ template-parameter. */
else if (declares_constrained_type_template_parameter (type))
default_argument
= cp_parser_default_type_template_argument (parser);
- // A constrained-type-specifier may declare a template-template-parameter.
+ /* A constrained-type-specifier may declare a
+ template-template-parameter. */
else if (declares_constrained_template_template_parameter (type))
default_argument
= cp_parser_default_template_template_argument (parser);
|| (decl_specifiers.type
&& PACK_EXPANSION_P (decl_specifiers.type)))
{
- /* Find the name of the parameter pack. */
+ /* Find the name of the parameter pack. */
cp_declarator *id_declarator = declarator;
while (id_declarator && id_declarator->kind != cdk_id)
id_declarator = id_declarator->declarator;
-
+
if (id_declarator && id_declarator->kind == cdk_id)
error_at (declarator_token_start->location,
template_parm_p
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");
+ "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");
+ "available with %<-std=c++2a%> or %<-std=gnu++2a%>");
}
/* Begin the function body. */
production is used). The TREE_TYPE for the CONSTRUCTOR will be
NULL_TREE. There is no way to detect whether or not the optional
trailing `,' was provided. NON_CONSTANT_P is as for
- cp_parser_initializer. */
+ cp_parser_initializer. */
static cp_expr
cp_parser_braced_list (cp_parser* parser, bool* non_constant_p)
/* 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);
bool array_designator_p
= (cp_parser_skip_to_closing_square_bracket (parser)
&& cp_lexer_next_token_is (parser->lexer, CPP_EQ));
-
+
/* Roll back the tokens we skipped. */
cp_lexer_rollback_tokens (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. */
{
if (IDENTIFIER_MARKED (designator))
{
- error_at (cp_expr_loc_or_loc (val, input_location),
+ error_at (cp_expr_loc_or_input_loc (val),
"%<.%s%> designator used multiple times in "
"the same initializer list",
IDENTIFIER_POINTER (designator));
IDENTIFIER_MARKED (designator) = 0;
}
+ *designated = first_designator != NULL_TREE;
return v;
}
/* In Objective-C 2.0, a classname followed by '.' starts a
dot-syntax expression, and it's not a type-name. */
|| (c_dialect_objc ()
- && cp_lexer_peek_token (parser->lexer)->type == CPP_DOT
+ && cp_lexer_peek_token (parser->lexer)->type == CPP_DOT
&& objc_is_class_name (decl)))
decl = error_mark_node;
return decl;
}
+/* Make sure that any member-function parameters are in scope.
+ For instance, a function's noexcept-specifier can use the function's
+ parameters:
+
+ struct S {
+ void fn (int p) noexcept(noexcept(p));
+ };
+
+ so we need to make sure name lookup can find them. This is used
+ when we delay parsing of the noexcept-specifier. */
+
+static void
+inject_parm_decls (tree decl)
+{
+ begin_scope (sk_function_parms, decl);
+ tree args = DECL_ARGUMENTS (decl);
+
+ do_push_parm_decls (decl, args, /*nonparms=*/NULL);
+}
+
+/* Undo the effects of inject_parm_decls. */
+
+static void
+pop_injected_parms (void)
+{
+ pop_bindings_and_leave_scope ();
+}
+
/* Parse a class-specifier.
class-specifier:
vec_safe_truncate (unparsed_classes, 0);
after_nsdmi_defaulted_late_checks (type);
+ /* If there are noexcept-specifiers that have not yet been processed,
+ take care of them now. */
+ class_type = NULL_TREE;
+ pushed_scope = NULL_TREE;
+ FOR_EACH_VEC_SAFE_ELT (unparsed_noexcepts, ix, decl)
+ {
+ tree ctx = DECL_CONTEXT (decl);
+ if (class_type != ctx)
+ {
+ if (pushed_scope)
+ pop_scope (pushed_scope);
+ class_type = ctx;
+ pushed_scope = push_scope (class_type);
+ }
+
+ tree spec = TYPE_RAISES_EXCEPTIONS (TREE_TYPE (decl));
+ spec = TREE_PURPOSE (spec);
+
+ /* Make sure that any template parameters are in scope. */
+ maybe_begin_member_template_processing (decl);
+
+ /* Make sure that any member-function parameters are in scope. */
+ inject_parm_decls (decl);
+
+ /* 'this' is not allowed in static member functions. */
+ unsigned char local_variables_forbidden_p
+ = parser->local_variables_forbidden_p;
+ if (DECL_THIS_STATIC (decl))
+ parser->local_variables_forbidden_p |= THIS_FORBIDDEN;
+
+ /* Now we can parse the noexcept-specifier. */
+ spec = cp_parser_late_noexcept_specifier (parser, spec);
+
+ if (spec != error_mark_node)
+ TREE_TYPE (decl) = build_exception_variant (TREE_TYPE (decl), spec);
+
+ /* Restore the state of local_variables_forbidden_p. */
+ parser->local_variables_forbidden_p = local_variables_forbidden_p;
+
+ /* The finish_struct call above performed various override checking,
+ but it skipped unparsed noexcept-specifier operands. Now that we
+ have resolved them, check again. */
+ noexcept_override_late_checks (type, decl);
+
+ /* Remove any member-function parameters from the symbol table. */
+ pop_injected_parms ();
+
+ /* Remove any template parameters from the symbol table. */
+ maybe_end_member_template_processing ();
+ }
+ vec_safe_truncate (unparsed_noexcepts, 0);
+ if (pushed_scope)
+ pop_scope (pushed_scope);
+
/* Now parse the body of the functions. */
if (flag_openmp)
{
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);
if (pedantic && tag_type == typename_type && cxx_dialect < cxx17)
/* typename is not allowed in a template template parameter
by the standard until C++17. */
- pedwarn (token->location, OPT_Wpedantic,
+ 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%>");
member-declarator:
declarator attributes [opt] pure-specifier [opt]
declarator attributes [opt] constant-initializer [opt]
- identifier [opt] attributes [opt] : constant-expression
+ identifier [opt] attributes [opt] : constant-expression
C++0x Extensions:
&& 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)
}
}
else
- {
+ {
/* Look for attributes that apply to the bitfield after
the `:' token and width. This is where GCC used to
parse attributes in the past, pedwarn if there is
tree asm_specification;
int ctor_dtor_or_conv_p;
bool static_p = (decl_specifiers.storage_class == sc_static);
+ cp_parser_flags flags = CP_PARSER_FLAGS_TYPENAME_OPTIONAL;
+ if (!friend_p
+ && !decl_spec_seq_has_spec_p (&decl_specifiers, ds_typedef))
+ flags |= CP_PARSER_FLAGS_DELAY_NOEXCEPT;
/* Parse the declarator. */
declarator
= cp_parser_declarator (parser, CP_PARSER_DECLARATOR_NAMED,
- CP_PARSER_FLAGS_TYPENAME_OPTIONAL,
+ flags,
&ctor_dtor_or_conv_p,
/*parenthesized_p=*/NULL,
/*member_p=*/true,
/* Exception handling [gram.exception] */
+/* Save the tokens that make up the noexcept-specifier for a member-function.
+ Returns a DEFERRED_PARSE. */
+
+static tree
+cp_parser_save_noexcept (cp_parser *parser)
+{
+ cp_token *first = parser->lexer->next_token;
+ /* We want everything up to, including, the final ')'. */
+ cp_parser_cache_group (parser, CPP_CLOSE_PAREN, /*depth=*/0);
+ cp_token *last = parser->lexer->next_token;
+
+ /* As with default arguments and NSDMIs, make use of DEFERRED_PARSE
+ to carry the information we will need. */
+ tree expr = make_node (DEFERRED_PARSE);
+ /* Save away the noexcept-specifier; we will process it when the
+ class is complete. */
+ DEFPARSE_TOKENS (expr) = cp_token_cache_new (first, last);
+ expr = build_tree_list (expr, NULL_TREE);
+ return expr;
+}
+
+/* Used for late processing of noexcept-specifiers of member-functions.
+ DEFAULT_ARG is the unparsed operand of a noexcept-specifier which
+ we saved for later; parse it now. */
+
+static tree
+cp_parser_late_noexcept_specifier (cp_parser *parser, tree default_arg)
+{
+ /* Make sure we've gotten something that hasn't been parsed yet. */
+ gcc_assert (TREE_CODE (default_arg) == DEFERRED_PARSE);
+
+ push_unparsed_function_queues (parser);
+
+ /* Push the saved tokens for the noexcept-specifier onto the parser's
+ lexer stack. */
+ cp_token_cache *tokens = DEFPARSE_TOKENS (default_arg);
+ cp_parser_push_lexer_for_tokens (parser, tokens);
+
+ /* Parse the cached noexcept-specifier. */
+ tree parsed_arg
+ = cp_parser_noexcept_specification_opt (parser,
+ CP_PARSER_FLAGS_NONE,
+ /*require_constexpr=*/true,
+ /*consumed_expr=*/NULL,
+ /*return_cond=*/false);
+
+ /* Revert to the main lexer. */
+ cp_parser_pop_lexer (parser);
+
+ /* Restore the queue. */
+ pop_unparsed_function_queues (parser);
+
+ /* And we're done. */
+ return parsed_arg;
+}
+
+/* Perform late checking of overriding function with respect to their
+ noexcept-specifiers. TYPE is the class and FNDECL is the function
+ that potentially overrides some virtual function with the same
+ signature. */
+
+static void
+noexcept_override_late_checks (tree type, tree fndecl)
+{
+ tree binfo = TYPE_BINFO (type);
+ tree base_binfo;
+
+ if (DECL_STATIC_FUNCTION_P (fndecl))
+ return;
+
+ for (int i = 0; BINFO_BASE_ITERATE (binfo, i, base_binfo); ++i)
+ {
+ tree basetype = BINFO_TYPE (base_binfo);
+
+ if (!TYPE_POLYMORPHIC_P (basetype))
+ continue;
+
+ tree fn = look_for_overrides_here (basetype, fndecl);
+ if (fn)
+ maybe_check_overriding_exception_spec (fndecl, fn);
+ }
+}
+
/* Parse an (optional) noexcept-specification.
noexcept-specification:
expression if parentheses follow noexcept, or return BOOLEAN_TRUE_NODE if
there are no parentheses. CONSUMED_EXPR will be set accordingly.
Otherwise, returns a noexcept specification unless RETURN_COND is true,
- in which case a boolean condition is returned instead. */
+ in which case a boolean condition is returned instead. The parser flags
+ FLAGS is used to control parsing. */
static tree
cp_parser_noexcept_specification_opt (cp_parser* parser,
+ cp_parser_flags flags,
bool require_constexpr,
bool* consumed_expr,
bool return_cond)
if (cp_parser_is_keyword (token, RID_NOEXCEPT))
{
tree expr;
+
+ /* [class.mem]/6 says that a noexcept-specifer (within the
+ member-specification of the class) is a complete-class context of
+ a class. So, if the noexcept-specifier has the optional expression,
+ just save the tokens, and reparse this after we're done with the
+ class. */
+ const bool literal_p
+ = ((cp_lexer_nth_token_is (parser->lexer, 3, CPP_NUMBER)
+ || cp_lexer_nth_token_is (parser->lexer, 3, CPP_KEYWORD))
+ && cp_lexer_nth_token_is (parser->lexer, 4, CPP_CLOSE_PAREN));
+
+ if (cp_lexer_nth_token_is (parser->lexer, 2, CPP_OPEN_PAREN)
+ /* No need to delay parsing for a number literal or true/false. */
+ && !literal_p
+ && at_class_scope_p ()
+ /* We don't delay parsing for friend member functions,
+ alias-declarations, and typedefs, even though the standard seems
+ to require it. */
+ && (flags & CP_PARSER_FLAGS_DELAY_NOEXCEPT)
+ && TYPE_BEING_DEFINED (current_class_type)
+ && !LAMBDA_TYPE_P (current_class_type))
+ return cp_parser_save_noexcept (parser);
+
cp_lexer_consume_token (parser->lexer);
if (cp_lexer_peek_token (parser->lexer)->type == CPP_OPEN_PAREN)
throw ( type-id-list [opt] )
Returns a TREE_LIST representing the exception-specification. The
- TREE_VALUE of each node is a type. */
+ TREE_VALUE of each node is a type. The parser flags FLAGS is used to
+ control parsing. */
static tree
-cp_parser_exception_specification_opt (cp_parser* parser)
+cp_parser_exception_specification_opt (cp_parser* parser, cp_parser_flags flags)
{
cp_token *token;
tree type_id_list;
token = cp_lexer_peek_token (parser->lexer);
/* Is it a noexcept-specification? */
- type_id_list = cp_parser_noexcept_specification_opt (parser, true, NULL,
- false);
+ type_id_list
+ = cp_parser_noexcept_specification_opt (parser, flags,
+ /*require_constexpr=*/true,
+ /*consumed_expr=*/NULL,
+ /*return_cond=*/false);
if (type_id_list != NULL_TREE)
return type_id_list;
&& cxx_dialect < cxx2a)
pedwarn (input_location, 0,
"%<try%> in %<constexpr%> function only "
- "available with -std=c++2a or -std=gnu++2a");
+ "available with %<-std=c++2a%> or %<-std=gnu++2a%>");
try_block = begin_try_block ();
cp_parser_compound_statement (parser, NULL, BCS_TRY_BLOCK, false);
/* Look for the `)'. */
parens.require_close (parser);
- if (name == error_mark_node
- || string_literal == error_mark_node
+ if (name == error_mark_node
+ || string_literal == error_mark_node
|| expression == error_mark_node)
invalid_operands = true;
/* Save away the identifier that indicates which attribute
this is. */
- identifier = (token->type == CPP_KEYWORD)
+ identifier = (token->type == CPP_KEYWORD)
/* For keywords, use the canonical spelling, not the
parsed identifier. */
? ridpointers[(int) token->keyword]
vec<tree, va_gc> *vec;
int attr_flag = (attribute_takes_identifier_p (identifier)
? id_attr : normal_attr);
- vec = cp_parser_parenthesized_expression_list
- (parser, attr_flag, /*cast_p=*/false,
- /*allow_expansion_p=*/false,
+ vec = cp_parser_parenthesized_expression_list
+ (parser, attr_flag, /*cast_p=*/false,
+ /*allow_expansion_p=*/false,
/*non_constant_p=*/NULL);
if (vec == NULL)
arguments = error_mark_node;
attr_id = canonicalize_attr_name (attr_id);
attribute = build_tree_list (build_tree_list (NULL_TREE, attr_id),
NULL_TREE);
- /* C++11 noreturn attribute is equivalent to GNU's. */
- if (is_attribute_p ("noreturn", attr_id))
- TREE_PURPOSE (TREE_PURPOSE (attribute)) = gnu_identifier;
+ /* We used to treat C++11 noreturn attribute as equivalent to GNU's,
+ but no longer: we have to be able to tell [[noreturn]] and
+ __attribute__((noreturn)) apart. */
/* C++14 deprecated attribute is equivalent to GNU's. */
- else if (is_attribute_p ("deprecated", attr_id))
+ if (is_attribute_p ("deprecated", attr_id))
TREE_PURPOSE (TREE_PURPOSE (attribute)) = gnu_identifier;
/* C++17 fallthrough attribute is equivalent to GNU's. */
else if (is_attribute_p ("fallthrough", attr_id))
vec<tree, va_gc> *vec;
int attr_flag = normal_attr;
+ /* Maybe we don't expect to see any arguments for this attribute. */
+ const attribute_spec *as
+ = lookup_attribute_spec (TREE_PURPOSE (attribute));
+ if (as && as->max_length == 0)
+ {
+ error_at (token->location, "%qE attribute does not take any arguments",
+ attr_id);
+ cp_parser_skip_to_closing_parenthesis (parser,
+ /*recovering=*/true,
+ /*or_comma=*/false,
+ /*consume_paren=*/true);
+ return error_mark_node;
+ }
+
if (attr_ns == gnu_identifier
&& attribute_takes_identifier_p (attr_id))
/* A GNU attribute that takes an identifier in parameter. */
&& !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);
if (alignas_expr == error_mark_node)
return error_mark_node;
+ /* Missing ')' means the code cannot possibly be valid; go ahead
+ and commit to make sure we issue a hard error. */
+ if (cp_parser_uncommitted_to_tentative_parse_p (parser)
+ && cp_lexer_next_token_is_not (parser->lexer, CPP_CLOSE_PAREN))
+ cp_parser_commit_to_tentative_parse (parser);
+
if (!parens.require_close (parser))
return error_mark_node;
&& 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);
template_id_p = true;
}
- return cp_parser_check_template_parameters
+ return cp_parser_check_template_parameters
(parser, num_templates, template_id_p, declarator_location,
declarator);
}
{
if (declarator && !current_function_decl)
error_at (location, "specializing member %<%T::%E%> "
- "requires %<template<>%> syntax",
+ "requires %<template<>%> syntax",
declarator->u.id.qualifying_scope,
declarator->u.id.unqualified_name);
else if (declarator)
error_at (location, "invalid declaration of %<%T::%E%>",
declarator->u.id.qualifying_scope,
declarator->u.id.unqualified_name);
- else
+ else
error_at (location, "too few template-parameter-lists");
return false;
}
/* 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)
+ /* A parameter declaration can also begin with [[attribute]]. */
+ && !cp_next_tokens_can_be_std_attribute_p (parser))
{
tree type;
tree pushed_scope = NULL_TREE;
= 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 (!ok)
{
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",
- decl);
+ error_at (DECL_SOURCE_LOCATION (decl), "literal operator "
+ "template %qD has invalid parameter list; expected "
+ "non-type template parameter pack %<<char...>%> or "
+ "single non-type parameter of class type",
+ decl);
else
- error ("literal operator template %qD has invalid parameter list."
- " Expected non-type template parameter pack <char...>",
- decl);
+ error_at (DECL_SOURCE_LOCATION (decl), "literal operator "
+ "template %qD has invalid parameter list; expected "
+ "non-type template parameter pack %<<char...>%>",
+ decl);
}
}
if (cp_parser_declares_only_class_p (parser)
|| (declares_class_or_enum & 2))
{
- // If this is a declaration, but not a definition, associate
- // any constraints with the type declaration. Constraints
- // are associated with definitions in cp_parser_class_specifier.
+ /* If this is a declaration, but not a definition, associate
+ any constraints with the type declaration. Constraints
+ are associated with definitions in cp_parser_class_specifier. */
if (declares_class_or_enum == 1)
associate_classtype_constraints (decl_specifiers.type);
^~~~~~~~~~~~~~~
with caret == start at the start of the type name,
finishing at the closing brace. */
- location_t finish_loc
- = get_finish (cp_lexer_previous_token (parser->lexer)->location);
location_t combined_loc = make_location (start_loc, start_loc,
- finish_loc);
+ parser->lexer);
cast.set_location (combined_loc);
return cast;
}
^~~~~~~~
with caret == start at the start of the type name,
finishing at the closing paren. */
- location_t finish_loc
- = get_finish (cp_lexer_previous_token (parser->lexer)->location);
- location_t combined_loc = make_location (start_loc, start_loc, finish_loc);
+ location_t combined_loc = make_location (start_loc, start_loc, parser->lexer);
cast.set_location (combined_loc);
return cast;
}
return error_mark_node;
}
- /* Remember it, if there default args to post process. */
+ /* Remember it, if there are default args to post process. */
cp_parser_save_default_args (parser, fn);
/* Save away the tokens that make up the body of the
}
/* Save the tokens that make up the in-class initializer for a non-static
- data member. Returns a DEFAULT_ARG. */
+ data member. Returns a DEFERRED_PARSE. */
static tree
cp_parser_save_nsdmi (cp_parser* parser)
vec_safe_push (unparsed_funs_with_default_args, entry);
break;
}
+
+ /* Remember if there is a noexcept-specifier to post process. */
+ tree spec = TYPE_RAISES_EXCEPTIONS (TREE_TYPE (decl));
+ if (UNPARSED_NOEXCEPT_SPEC_P (spec))
+ vec_safe_push (unparsed_noexcepts, decl);
}
/* DEFAULT_ARG contains the saved tokens for the initializer of DECL,
/* Push the saved tokens for the default argument onto the parser's
lexer stack. */
- tokens = DEFARG_TOKENS (default_arg);
+ tokens = DEFPARSE_TOKENS (default_arg);
cp_parser_push_lexer_for_tokens (parser, tokens);
start_lambda_scope (decl);
}
/* FN is a FUNCTION_DECL which may contains a parameter with an
- unparsed DEFAULT_ARG. Parse the default args now. This function
+ unparsed DEFERRED_PARSE. Parse the default args now. This function
assumes that the current scope is the scope in which the default
argument should be processed. */
if (!default_arg)
continue;
- if (TREE_CODE (default_arg) != DEFAULT_ARG)
+ if (TREE_CODE (default_arg) != DEFERRED_PARSE)
/* This can happen for a friend declaration for a function
already declared with default arguments. */
continue;
TREE_PURPOSE (parm) = parsed_arg;
/* Update any instantiations we've already created. */
- for (insts = DEFARG_INSTANTIATIONS (default_arg), ix = 0;
+ for (insts = DEFPARSE_INSTANTIATIONS (default_arg), ix = 0;
vec_safe_iterate (insts, ix, ©); ix++)
TREE_PURPOSE (copy) = parsed_arg;
}
{
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. */
{
tree type = NULL_TREE;
+ tentative_firewall firewall (parser);
+
/* We can't be sure yet whether we're looking at a type-id or an
expression. */
cp_parser_parse_tentatively (parser);
/* If all went well, then we're done. */
if (cp_parser_parse_definitely (parser))
expr = type;
- }
+ else
+ {
+ /* Commit to the tentative_firewall so we get syntax errors. */
+ cp_parser_commit_to_tentative_parse (parser);
- /* If the type-id production did not work out, then we must be
- looking at the unary-expression production. */
- if (!expr)
+ expr = cp_parser_unary_expression (parser);
+ }
+ }
+ else
expr = cp_parser_unary_expression (parser);
/* Go back to evaluating 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_specs->storage_class = storage_class;
set_and_check_decl_spec_loc (decl_specs, ds_storage_class, token);
- /* A storage class specifier cannot be applied alongside a typedef
- specifier. If there is a typedef specifier present then set
+ /* A storage class specifier cannot be applied alongside a typedef
+ specifier. If there is a typedef specifier present then set
conflicting_specifiers_p which will trigger an error later
on in grokdeclarator. */
if (decl_spec_seq_has_spec_p (decl_specs, ds_typedef))
{
decl_specs->locations[ds_long_long] = location;
pedwarn_cxx98 (location,
- OPT_Wlong_long,
+ OPT_Wlong_long,
"ISO C++ 1998 does not support %<long long%>");
}
}
"typedef",
"using",
"constexpr",
- "__complex"
+ "__complex",
+ "constinit"
};
gcc_rich_location richloc (location);
richloc.add_fixit_remove ();
cp_token *token;
token = cp_lexer_peek_token (parser->lexer);
- return (token->type == CPP_COMMA
+ return (token->type == CPP_COMMA
|| token->type == CPP_GREATER
|| token->type == CPP_ELLIPSIS
|| ((cxx_dialect != cxx98) && token->type == CPP_RSHIFT));
token = cp_lexer_consume_token (parser->lexer);
}
- /* Create a DEFAULT_ARG to represent the unparsed default
+ /* Create a DEFERRED_PARSE to represent the unparsed default
argument. */
- default_argument = make_node (DEFAULT_ARG);
- DEFARG_TOKENS (default_argument)
+ default_argument = make_node (DEFERRED_PARSE);
+ DEFPARSE_TOKENS (default_argument)
= cp_token_cache_new (first_token, token);
- DEFARG_INSTANTIATIONS (default_argument) = NULL;
+ DEFPARSE_INSTANTIATIONS (default_argument) = NULL;
return default_argument;
}
-/* A location to use for diagnostics about an unparsed DEFAULT_ARG. */
+/* A location to use for diagnostics about an unparsed DEFERRED_PARSE. */
location_t
-defarg_location (tree default_argument)
+defparse_location (tree default_argument)
{
- cp_token_cache *tokens = DEFARG_TOKENS (default_argument);
+ cp_token_cache *tokens = DEFPARSE_TOKENS (default_argument);
location_t start = tokens->first->location;
location_t end = tokens->last->location;
return make_location (start, start, end);
if (cp_parser_parse_definitely (parser))
return objc_get_class_reference (rcv);
-
+
cp_parser_error (parser, "objective-c++ message receiver expected");
return error_mark_node;
}
if (!type)
{
- error_at (token->location,
+ error_at (token->location,
"%<@encode%> must specify a type as an argument");
return error_mark_node;
}
@encode(int)
^~~~~~~~~~~~
with caret==start at the @ token, finishing at the close paren. */
- location_t combined_loc
- = make_location (start_loc, start_loc,
- cp_lexer_previous_token (parser->lexer)->location);
+ location_t combined_loc = make_location (start_loc, start_loc, parser->lexer);
return cp_expr (objc_build_encode_expr (type), combined_loc);
}
@protocol(prot)
^~~~~~~~~~~~~~~
with caret==start at the @ token, finishing at the close paren. */
- location_t combined_loc
- = make_location (start_loc, start_loc,
- cp_lexer_previous_token (parser->lexer)->location);
+ location_t combined_loc = make_location (start_loc, start_loc, parser->lexer);
tree result = objc_build_protocol_expr (proto);
protected_set_expr_location (result, combined_loc);
return result;
@selector(func)
^~~~~~~~~~~~~~~
with caret==start at the @ token, finishing at the close paren. */
- location_t combined_loc
- = make_location (loc, loc,
- cp_lexer_previous_token (parser->lexer)->location);
+ location_t combined_loc = make_location (loc, loc, parser->lexer);
tree result = objc_build_selector_expr (combined_loc, sel_seq);
/* TODO: objc_build_selector_expr doesn't always honor the location. */
protected_set_expr_location (result, combined_loc);
identifier = cp_parser_identifier (parser);
if (identifier == error_mark_node)
- return error_mark_node;
+ return error_mark_node;
list = build_tree_list (NULL_TREE, identifier);
sep = cp_lexer_peek_token (parser->lexer);
identifier));
sep = cp_lexer_peek_token (parser->lexer);
}
-
+
return list;
}
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))
if (cp_lexer_next_token_is_not (parser->lexer, CPP_CLOSE_PAREN))
{
cp_type = cp_parser_type_id (parser);
-
+
/* If the type could not be parsed, an error has already
been produced. For error recovery, behave as if it had
not been specified, which will use the default type
if (cp_lexer_next_token_is (parser->lexer, CPP_SEMICOLON)
|| cp_lexer_next_token_is (parser->lexer, CPP_OPEN_BRACE))
return params;
- cp_parser_error (parser,
+ cp_parser_error (parser,
"method attributes must be specified at the end");
return error_mark_node;
}
/* Parse the non-keyword Objective-C params. */
static tree
-cp_parser_objc_method_tail_params_opt (cp_parser* parser, bool *ellipsisp,
+cp_parser_objc_method_tail_params_opt (cp_parser* parser, bool *ellipsisp,
tree* attributes)
{
tree params = make_node (TREE_LIST);
|| cp_lexer_next_token_is (parser->lexer, CPP_OPEN_BRACE))
return params;
}
- else
- /* We have an error, but parse the attributes, so that we can
+ else
+ /* We have an error, but parse the attributes, so that we can
carry on. */
*attributes = cp_parser_attributes_opt (parser);
- cp_parser_error (parser,
+ cp_parser_error (parser,
"method attributes must be specified at the end");
return error_mark_node;
}
static bool
cp_parser_objc_method_maybe_bad_prefix_attributes (cp_parser* parser)
{
- tree tattr;
+ tree tattr;
cp_lexer_save_tokens (parser->lexer);
tattr = cp_parser_attributes_opt (parser);
gcc_assert (tattr) ;
-
+
/* If the attributes are followed by a method introducer, this is not allowed.
Dump the attributes and flag the situation. */
if (cp_lexer_next_token_is (parser->lexer, CPP_PLUS)
/* Otherwise, the attributes introduce some interstitial code, possibly so
rewind to allow that check. */
cp_lexer_rollback_tokens (parser->lexer);
- return false;
+ return false;
}
/* Parse an Objective-C method prototype list. */
}
else if (token->keyword == RID_AT_PROPERTY)
cp_parser_objc_at_property_declaration (parser);
- else if (token->keyword == RID_ATTRIBUTE
+ else if (token->keyword == RID_ATTRIBUTE
&& cp_parser_objc_method_maybe_bad_prefix_attributes(parser))
- warning_at (cp_lexer_peek_token (parser->lexer)->location,
- OPT_Wattributes,
+ warning_at (cp_lexer_peek_token (parser->lexer)->location,
+ OPT_Wattributes,
"prefix attributes are ignored for methods");
else
/* Allow for interspersed non-ObjC++ code. */
cp_lexer_consume_token (parser->lexer);
ptk = cp_lexer_peek_token (parser->lexer);
- if (!(ptk->type == CPP_PLUS || ptk->type == CPP_MINUS
+ if (!(ptk->type == CPP_PLUS || ptk->type == CPP_MINUS
|| ptk->type == CPP_EOF || ptk->keyword == RID_AT_END))
{
perform_deferred_access_checks (tf_warning_or_error);
cp_parser_objc_at_synthesize_declaration (parser);
else if (token->keyword == RID_AT_DYNAMIC)
cp_parser_objc_at_dynamic_declaration (parser);
- else if (token->keyword == RID_ATTRIBUTE
+ else if (token->keyword == RID_ATTRIBUTE
&& cp_parser_objc_method_maybe_bad_prefix_attributes(parser))
warning_at (token->location, OPT_Wattributes,
"prefix attributes are ignored for methods");
cp_lexer_consume_token (parser->lexer); /* Eat '{'. */
token = cp_lexer_peek_token (parser->lexer);
- while (token->type != CPP_CLOSE_BRACE
+ while (token->type != CPP_CLOSE_BRACE
&& token->keyword != RID_AT_END && token->type != CPP_EOF)
{
cp_decl_specifier_seq declspecs;
/* auto, register, static, extern, mutable. */
if (declspecs.storage_class != sc_none)
{
- cp_parser_error (parser, "invalid type for instance variable");
+ cp_parser_error (parser, "invalid type for instance variable");
declspecs.storage_class = sc_none;
}
cp_parser_error (parser, "invalid type for instance variable");
declspecs.locations[ds_thread] = 0;
}
-
+
/* typedef. */
if (decl_spec_seq_has_spec_p (&declspecs, ds_typedef))
{
cp_parser_error (parser, "expected %<}%>");
/* Do not consume the RID_AT_END, so it will be read again as terminating
- the @interface of @implementation. */
+ the @interface of @implementation. */
if (token->keyword != RID_AT_END && token->type != CPP_EOF)
cp_lexer_consume_token (parser->lexer); /* Eat '}'. */
-
+
/* For historical reasons, we accept an optional semicolon. */
if (cp_lexer_next_token_is (parser->lexer, CPP_SEMICOLON))
cp_lexer_consume_token (parser->lexer);
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
/* Parse an Objective-C superclass or category. */
static void
-cp_parser_objc_superclass_or_category (cp_parser *parser,
+cp_parser_objc_superclass_or_category (cp_parser *parser,
bool iface_p,
tree *super,
tree *categ, bool *is_class_extension)
Returns NULL_TREE.
PS: This function is identical to c_parser_objc_try_catch_finally_statement
- for C. Keep them in sync. */
+ for C. Keep them in sync. */
static tree
cp_parser_objc_try_catch_finally_statement (cp_parser *parser)
going. */
if (cp_lexer_next_token_is (parser->lexer, CPP_CLOSE_PAREN))
cp_lexer_consume_token (parser->lexer);
-
+
/* If these is no immediate closing parenthesis, the user
probably doesn't know that parenthesis are required at
all (ie, they typed "@catch NSException *e"). So, just
return error_mark_node;
}
-/* If we are compiling ObjC++ and we see an __attribute__ we neeed to
+/* If we are compiling ObjC++ and we see an __attribute__ we neeed to
look ahead to see if an objc keyword follows the attributes. This
- is to detect the use of prefix attributes on ObjC @interface and
+ is to detect the use of prefix attributes on ObjC @interface and
@protocol. */
static bool
return true;
}
cp_lexer_rollback_tokens (parser->lexer);
- return false;
+ return false;
}
/* This routine is a minimal replacement for
cp_parser_error (parser, "invalid type for property");
declspecs.storage_class = sc_none;
}
-
+
/* thread_local. */
if (decl_spec_seq_has_spec_p (&declspecs, ds_thread))
{
cp_parser_error (parser, "invalid type for property");
declspecs.locations[ds_thread] = 0;
}
-
+
/* typedef. */
if (decl_spec_seq_has_spec_p (&declspecs, ds_typedef))
{
if (decl == error_mark_node || decl == NULL_TREE)
return error_mark_node;
-
+
/* Reset PREFIX_ATTRIBUTES. */
if (attributes != error_mark_node)
{
PS: This function is identical to
c_parser_objc_at_property_declaration for C. Keep them in sync. */
-static void
+static void
cp_parser_objc_at_property_declaration (cp_parser *parser)
{
/* The following variables hold the attributes of the properties as
/* Comma-separated properties are chained together in
reverse order; add them one by one. */
properties = nreverse (properties);
-
+
for (; properties; properties = TREE_CHAIN (properties))
objc_add_property_declaration (loc, copy_node (properties),
property_readonly, property_readwrite,
property_copy, property_nonatomic,
property_getter_ident, property_setter_ident);
}
-
+
cp_parser_consume_semicolon_at_end_of_statement (parser);
}
PS: This function is identical to c_parser_objc_at_synthesize_declaration
for C. Keep them in sync.
*/
-static void
+static void
cp_parser_objc_at_synthesize_declaration (cp_parser *parser)
{
tree list = NULL_TREE;
PS: This function is identical to c_parser_objc_at_dynamic_declaration
for C. Keep them in sync.
*/
-static void
+static void
cp_parser_objc_at_dynamic_declaration (cp_parser *parser)
{
tree list = NULL_TREE;
else if (!strcmp ("async", p))
result = PRAGMA_OACC_CLAUSE_ASYNC;
break;
+ case 'b':
+ if (!strcmp ("bind", p))
+ result = PRAGMA_OMP_CLAUSE_BIND;
+ break;
case 'c':
if (!strcmp ("collapse", p))
result = PRAGMA_OMP_CLAUSE_COLLAPSE;
result = PRAGMA_OACC_CLAUSE_DEVICEPTR;
else if (!strcmp ("device_resident", p))
result = PRAGMA_OACC_CLAUSE_DEVICE_RESIDENT;
+ else if (!strcmp ("device_type", p))
+ result = PRAGMA_OMP_CLAUSE_DEVICE_TYPE;
else if (!strcmp ("dist_schedule", p))
result = PRAGMA_OMP_CLAUSE_DIST_SCHEDULE;
break;
case 'o':
if (!strcmp ("ordered", p))
result = PRAGMA_OMP_CLAUSE_ORDERED;
+ else if (!strcmp ("order", p))
+ result = PRAGMA_OMP_CLAUSE_ORDER;
break;
case 'p':
if (!strcmp ("parallel", p))
result = PRAGMA_OMP_CLAUSE_UNTIED;
else if (!strcmp ("use_device", p))
result = PRAGMA_OACC_CLAUSE_USE_DEVICE;
+ else if (!strcmp ("use_device_addr", p))
+ result = PRAGMA_OMP_CLAUSE_USE_DEVICE_ADDR;
else if (!strcmp ("use_device_ptr", p))
result = PRAGMA_OMP_CLAUSE_USE_DEVICE_PTR;
break;
check_no_duplicate_clause (tree clauses, enum omp_clause_code code,
const char *name, location_t location)
{
- tree c;
-
- for (c = clauses; c ; c = OMP_CLAUSE_CHAIN (c))
- if (OMP_CLAUSE_CODE (c) == code)
- {
- error_at (location, "too many %qs clauses", name);
- break;
- }
+ if (omp_find_clause (clauses, code))
+ error_at (location, "too many %qs clauses", name);
}
/* OpenMP 2.5:
{
if (tile && !cp_parser_require (parser, CPP_COMMA, RT_COMMA))
return list;
-
+
if (cp_lexer_next_token_is (parser->lexer, CPP_MULT)
&& (cp_lexer_nth_token_is (parser->lexer, 2, CPP_COMMA)
|| cp_lexer_nth_token_is (parser->lexer, 2, CPP_CLOSE_PAREN)))
case OMP_TARGET_DATA: p = "target data"; break;
case OMP_TARGET: p = "target"; break;
case OMP_TARGET_UPDATE: p = "target update"; break;
- case OMP_TARGET_ENTER_DATA: p = "enter data"; break;
- case OMP_TARGET_EXIT_DATA: p = "exit data"; break;
+ case OMP_TARGET_ENTER_DATA: p = "target enter data"; break;
+ case OMP_TARGET_EXIT_DATA: p = "target exit data"; break;
default: gcc_unreachable ();
}
error_at (location, "too many %<if%> clauses with %qs modifier",
return list;
}
+/* OpenMP 5.0:
+ order ( concurrent ) */
+
+static tree
+cp_parser_omp_clause_order (cp_parser *parser, tree list, location_t location)
+{
+ tree c, id;
+ const char *p;
+
+ matching_parens parens;
+ if (!parens.require_open (parser))
+ return list;
+
+ if (!cp_lexer_next_token_is (parser->lexer, CPP_NAME))
+ {
+ cp_parser_error (parser, "expected %<concurrent%>");
+ goto out_err;
+ }
+ else
+ {
+ id = cp_lexer_peek_token (parser->lexer)->u.value;
+ p = IDENTIFIER_POINTER (id);
+ }
+ if (strcmp (p, "concurrent") != 0)
+ {
+ cp_parser_error (parser, "expected %<concurrent%>");
+ goto out_err;
+ }
+ cp_lexer_consume_token (parser->lexer);
+ if (!parens.require_close (parser))
+ goto out_err;
+
+ /* check_no_duplicate_clause (list, OMP_CLAUSE_ORDER, "order", location); */
+ c = build_omp_clause (location, OMP_CLAUSE_ORDER);
+ OMP_CLAUSE_CHAIN (c) = list;
+ return c;
+
+ out_err:
+ cp_parser_skip_to_closing_parenthesis (parser, /*recovering=*/true,
+ /*or_comma=*/false,
+ /*consume_paren=*/true);
+ return list;
+}
+
+/* OpenMP 5.0:
+ bind ( teams | parallel | thread ) */
+
+static tree
+cp_parser_omp_clause_bind (cp_parser *parser, tree list,
+ location_t location)
+{
+ tree c;
+ const char *p;
+ enum omp_clause_bind_kind kind = OMP_CLAUSE_BIND_THREAD;
+
+ matching_parens parens;
+ if (!parens.require_open (parser))
+ return list;
+
+ if (!cp_lexer_next_token_is (parser->lexer, CPP_NAME))
+ {
+ invalid:
+ cp_parser_error (parser,
+ "expected %<teams%>, %<parallel%> or %<thread%>");
+ goto out_err;
+ }
+ else
+ {
+ tree id = cp_lexer_peek_token (parser->lexer)->u.value;
+ p = IDENTIFIER_POINTER (id);
+ }
+ if (strcmp (p, "teams") == 0)
+ kind = OMP_CLAUSE_BIND_TEAMS;
+ else if (strcmp (p, "parallel") == 0)
+ kind = OMP_CLAUSE_BIND_PARALLEL;
+ else if (strcmp (p, "thread") != 0)
+ goto invalid;
+ cp_lexer_consume_token (parser->lexer);
+ if (!parens.require_close (parser))
+ goto out_err;
+
+ /* check_no_duplicate_clause (list, OMP_CLAUSE_BIND, "bind", location); */
+ c = build_omp_clause (location, OMP_CLAUSE_BIND);
+ OMP_CLAUSE_BIND_KIND (c) = kind;
+ OMP_CLAUSE_CHAIN (c) = list;
+ return c;
+
+ out_err:
+ cp_parser_skip_to_closing_parenthesis (parser, /*recovering=*/true,
+ /*or_comma=*/false,
+ /*consume_paren=*/true);
+ return list;
+}
+
/* OpenMP 2.5:
ordered
if (strcmp (p, "task") == 0)
task = true;
else if (strcmp (p, "inscan") == 0)
- {
- inscan = true;
- sorry ("%<inscan%> modifier on %<reduction%> clause "
- "not supported yet");
- }
+ inscan = true;
if (task || inscan)
{
cp_lexer_consume_token (parser->lexer);
linear ( modifier ( variable-list ) : expression ) */
static tree
-cp_parser_omp_clause_linear (cp_parser *parser, tree list,
+cp_parser_omp_clause_linear (cp_parser *parser, tree list,
bool declare_simd)
{
tree nlist, c, step = integer_one_node;
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;
return list;
}
+/* OpenMP 5.0:
+ device_type ( host | nohost | any ) */
+
+static tree
+cp_parser_omp_clause_device_type (cp_parser *parser, tree list,
+ location_t location)
+{
+ tree c;
+ enum omp_clause_device_type_kind kind;
+
+ if (!cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN))
+ return list;
+
+ if (cp_lexer_next_token_is (parser->lexer, CPP_NAME))
+ {
+ tree id = cp_lexer_peek_token (parser->lexer)->u.value;
+ const char *p = IDENTIFIER_POINTER (id);
+
+ if (strcmp ("host", p) == 0)
+ kind = OMP_CLAUSE_DEVICE_TYPE_HOST;
+ else if (strcmp ("nohost", p) == 0)
+ kind = OMP_CLAUSE_DEVICE_TYPE_NOHOST;
+ else if (strcmp ("any", p) == 0)
+ kind = OMP_CLAUSE_DEVICE_TYPE_ANY;
+ else
+ goto invalid_kind;
+ }
+ else
+ goto invalid_kind;
+
+ cp_lexer_consume_token (parser->lexer);
+ if (!cp_parser_require (parser, CPP_CLOSE_PAREN, RT_COMMA_CLOSE_PAREN))
+ goto resync_fail;
+
+ c = build_omp_clause (location, OMP_CLAUSE_DEVICE_TYPE);
+ /* check_no_duplicate_clause (list, OMP_CLAUSE_DEVICE_TYPE, "device_type",
+ location); */
+ OMP_CLAUSE_DEVICE_TYPE_KIND (c) = kind;
+ OMP_CLAUSE_CHAIN (c) = list;
+ return c;
+
+ invalid_kind:
+ cp_parser_error (parser, "invalid depend kind");
+ resync_fail:
+ cp_parser_skip_to_closing_parenthesis (parser, /*recovering=*/true,
+ /*or_comma=*/false,
+ /*consume_paren=*/true);
+ return list;
+}
+
/* OpenACC:
async [( int-expr )] */
switch (c_kind)
{
+ case PRAGMA_OMP_CLAUSE_BIND:
+ clauses = cp_parser_omp_clause_bind (parser, clauses,
+ token->location);
+ c_name = "bind";
+ break;
case PRAGMA_OMP_CLAUSE_COLLAPSE:
clauses = cp_parser_omp_clause_collapse (parser, clauses,
token->location);
clauses);
c_name = "use_device_ptr";
break;
+ case PRAGMA_OMP_CLAUSE_USE_DEVICE_ADDR:
+ clauses = cp_parser_omp_var_list (parser, OMP_CLAUSE_USE_DEVICE_ADDR,
+ clauses);
+ c_name = "use_device_addr";
+ break;
case PRAGMA_OMP_CLAUSE_IS_DEVICE_PTR:
clauses = cp_parser_omp_var_list (parser, OMP_CLAUSE_IS_DEVICE_PTR,
clauses);
c_name = "mergeable";
break;
case PRAGMA_OMP_CLAUSE_NOWAIT:
- clauses = cp_parser_omp_clause_nowait (parser, clauses, token->location);
+ clauses = cp_parser_omp_clause_nowait (parser, clauses,
+ token->location);
c_name = "nowait";
break;
case PRAGMA_OMP_CLAUSE_NUM_TASKS:
token->location);
c_name = "num_threads";
break;
+ case PRAGMA_OMP_CLAUSE_ORDER:
+ clauses = cp_parser_omp_clause_order (parser, clauses,
+ token->location);
+ c_name = "order";
+ break;
case PRAGMA_OMP_CLAUSE_ORDERED:
clauses = cp_parser_omp_clause_ordered (parser, clauses,
token->location);
token->location);
c_name = "proc_bind";
break;
+ case PRAGMA_OMP_CLAUSE_DEVICE_TYPE:
+ clauses = cp_parser_omp_clause_device_type (parser, clauses,
+ token->location);
+ c_name = "device_type";
+ break;
case PRAGMA_OMP_CLAUSE_SAFELEN:
clauses = cp_parser_omp_clause_safelen (parser, clauses,
token->location);
|| CLASS_TYPE_P (TREE_TYPE (decl))))
return cond;
- return build_x_binary_op (cp_expr_loc_or_loc (cond, input_location),
+ return build_x_binary_op (cp_expr_loc_or_input_loc (cond),
TREE_CODE (cond),
TREE_OPERAND (cond, 0), ERROR_MARK,
TREE_OPERAND (cond, 1), ERROR_MARK,
static tree
cp_parser_omp_for_loop_init (cp_parser *parser,
tree &this_pre_body,
- vec<tree, va_gc> *&for_block,
+ releasing_vec &for_block,
tree &init,
tree &orig_init,
tree &decl,
attributes = cp_parser_attributes_opt (parser);
asm_specification = cp_parser_asm_specification_opt (parser);
- if (declarator == cp_error_declarator)
+ if (declarator == cp_error_declarator)
cp_parser_skip_to_end_of_statement (parser);
- else
+ else
{
tree pushed_scope, auto_node;
auto_node = type_uses_auto (TREE_TYPE (decl));
if (cp_lexer_next_token_is_not (parser->lexer, CPP_EQ))
{
- if (cp_lexer_next_token_is (parser->lexer,
+ if (cp_lexer_next_token_is (parser->lexer,
CPP_OPEN_PAREN))
error ("parenthesized initialization is not allowed in "
"OpenMP %<for%> loop");
&& !type_dependent_expression_p (decl))
goto non_class;
}
-
+
cp_finish_decl (decl, init, !is_non_constant_init,
asm_specification,
LOOKUP_ONLYCONVERTING);
pop_scope (pushed_scope);
}
}
- else
+ else
{
cp_id_kind idk;
/* If parsing a type specifier sequence failed, then
cp_finish_decomp (decl, decomp_first_name, decomp_cnt);
}
+/* OpenMP 5.0:
+
+ scan-loop-body:
+ { structured-block scan-directive structured-block } */
+
+static void
+cp_parser_omp_scan_loop_body (cp_parser *parser)
+{
+ tree substmt, clauses = NULL_TREE;
+
+ matching_braces braces;
+ if (!braces.require_open (parser))
+ return;
+
+ substmt = cp_parser_omp_structured_block (parser, NULL);
+ substmt = build2 (OMP_SCAN, void_type_node, substmt, NULL_TREE);
+ add_stmt (substmt);
+
+ cp_token *tok = cp_lexer_peek_token (parser->lexer);
+ if (cp_parser_pragma_kind (tok) == PRAGMA_OMP_SCAN)
+ {
+ enum omp_clause_code clause = OMP_CLAUSE_ERROR;
+
+ cp_lexer_consume_token (parser->lexer);
+
+ if (cp_lexer_next_token_is (parser->lexer, CPP_NAME))
+ {
+ tree id = cp_lexer_peek_token (parser->lexer)->u.value;
+ const char *p = IDENTIFIER_POINTER (id);
+ if (strcmp (p, "inclusive") == 0)
+ clause = OMP_CLAUSE_INCLUSIVE;
+ else if (strcmp (p, "exclusive") == 0)
+ clause = OMP_CLAUSE_EXCLUSIVE;
+ }
+ if (clause != OMP_CLAUSE_ERROR)
+ {
+ cp_lexer_consume_token (parser->lexer);
+ clauses = cp_parser_omp_var_list (parser, clause, NULL_TREE);
+ }
+ else
+ cp_parser_error (parser, "expected %<inclusive%> or "
+ "%<exclusive%> clause");
+
+ cp_parser_require_pragma_eol (parser, tok);
+ }
+ else
+ error ("expected %<#pragma omp scan%>");
+
+ clauses = finish_omp_clauses (clauses, C_ORT_OMP);
+ substmt = cp_parser_omp_structured_block (parser, NULL);
+ substmt = build2_loc (tok->location, OMP_SCAN, void_type_node, substmt,
+ clauses);
+ add_stmt (substmt);
+
+ braces.require_close (parser);
+}
+
/* Parse the restricted form of the for statement allowed by OpenMP. */
static tree
location_t loc_first;
bool collapse_err = false;
int i, collapse = 1, ordered = 0, count, nbraces = 0;
- vec<tree, va_gc> *for_block = make_tree_vector ();
+ releasing_vec for_block;
auto_vec<tree, 4> orig_inits;
bool tiling = false;
+ bool inscan = false;
for (cl = clauses; cl; cl = OMP_CLAUSE_CHAIN (cl))
if (OMP_CLAUSE_CODE (cl) == OMP_CLAUSE_COLLAPSE)
ordered_cl = cl;
ordered = tree_to_shwi (OMP_CLAUSE_ORDERED_EXPR (cl));
}
+ else if (OMP_CLAUSE_CODE (cl) == OMP_CLAUSE_REDUCTION
+ && OMP_CLAUSE_REDUCTION_INSCAN (cl)
+ && (code == OMP_SIMD || code == OMP_FOR))
+ inscan = true;
if (ordered && ordered < collapse)
{
real_decl = decl;
if (cclauses != NULL
&& cclauses[C_OMP_CLAUSE_SPLIT_PARALLEL] != NULL
- && real_decl != NULL_TREE)
+ && real_decl != NULL_TREE
+ && code != OMP_LOOP)
{
tree *c;
for (c = &cclauses[C_OMP_CLAUSE_SPLIT_PARALLEL]; *c ; )
}
if (c == NULL)
{
- if (code != OMP_SIMD)
+ if ((code == OMP_SIMD && collapse != 1) || code == OMP_LOOP)
+ c = build_omp_clause (loc, OMP_CLAUSE_LASTPRIVATE);
+ else if (code != OMP_SIMD)
c = build_omp_clause (loc, OMP_CLAUSE_PRIVATE);
- else if (collapse == 1)
- c = build_omp_clause (loc, OMP_CLAUSE_LINEAR);
else
- c = build_omp_clause (loc, OMP_CLAUSE_LASTPRIVATE);
+ c = build_omp_clause (loc, OMP_CLAUSE_LINEAR);
OMP_CLAUSE_DECL (c) = add_private_clause;
c = finish_omp_clauses (c, C_ORT_OMP);
if (c)
}
else
body = push_stmt_list ();
- cp_parser_statement (parser, NULL_TREE, false, if_p);
+ if (inscan)
+ cp_parser_omp_scan_loop_body (parser);
+ else
+ cp_parser_statement (parser, NULL_TREE, false, if_p);
if (orig_declv)
body = finish_omp_structured_block (body);
else
else
add_stmt (t);
}
- release_tree_vector (for_block);
return ret;
}
cclauses[i] = finish_omp_clauses (cclauses[i], C_ORT_OMP);
}
+/* OpenMP 5.0:
+ #pragma omp loop loop-clause[optseq] new-line
+ for-loop */
+
+#define OMP_LOOP_CLAUSE_MASK \
+ ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PRIVATE) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_LASTPRIVATE) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_REDUCTION) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_COLLAPSE) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_BIND) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_ORDER))
+
+static tree
+cp_parser_omp_loop (cp_parser *parser, cp_token *pragma_tok,
+ char *p_name, omp_clause_mask mask, tree *cclauses,
+ bool *if_p)
+{
+ tree clauses, sb, ret;
+ unsigned int save;
+ location_t loc = cp_lexer_peek_token (parser->lexer)->location;
+
+ strcat (p_name, " loop");
+ mask |= OMP_LOOP_CLAUSE_MASK;
+
+ clauses = cp_parser_omp_all_clauses (parser, mask, p_name, pragma_tok,
+ cclauses == NULL);
+ if (cclauses)
+ {
+ cp_omp_split_clauses (loc, OMP_LOOP, mask, clauses, cclauses);
+ clauses = cclauses[C_OMP_CLAUSE_SPLIT_LOOP];
+ }
+
+ keep_next_level (true);
+ sb = begin_omp_structured_block ();
+ save = cp_parser_begin_omp_structured_block (parser);
+
+ ret = cp_parser_omp_for_loop (parser, OMP_LOOP, clauses, cclauses, if_p);
+
+ cp_parser_end_omp_structured_block (parser, save);
+ add_stmt (finish_omp_for_block (finish_omp_structured_block (sb), ret));
+
+ return ret;
+}
+
/* OpenMP 4.0:
#pragma omp simd simd-clause[optseq] new-line
for-loop */
| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_REDUCTION) \
| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_COLLAPSE) \
| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_IF) \
- | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NONTEMPORAL))
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NONTEMPORAL) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_ORDER))
static tree
cp_parser_omp_simd (cp_parser *parser, cp_token *pragma_tok,
| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_ORDERED) \
| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_SCHEDULE) \
| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOWAIT) \
- | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_COLLAPSE))
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_COLLAPSE) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_ORDER))
static tree
cp_parser_omp_for (cp_parser *parser, cp_token *pragma_tok,
cp_parser_skip_to_pragma_eol (parser, pragma_tok);
return NULL_TREE;
}
- else if (cclauses == NULL && cp_lexer_next_token_is (parser->lexer, CPP_NAME))
+ else if (cp_lexer_next_token_is (parser->lexer, CPP_NAME))
{
tree id = cp_lexer_peek_token (parser->lexer)->u.value;
const char *p = IDENTIFIER_POINTER (id);
- if (strcmp (p, "master") == 0)
+ if (cclauses == NULL && strcmp (p, "master") == 0)
{
tree cclauses_buf[C_OMP_CLAUSE_SPLIT_COUNT];
cclauses = cclauses_buf;
return ret;
return stmt;
}
+ else if (strcmp (p, "loop") == 0)
+ {
+ tree cclauses_buf[C_OMP_CLAUSE_SPLIT_COUNT];
+ if (cclauses == NULL)
+ cclauses = cclauses_buf;
+
+ cp_lexer_consume_token (parser->lexer);
+ if (!flag_openmp) /* flag_openmp_simd */
+ return cp_parser_omp_loop (parser, pragma_tok, p_name, mask,
+ cclauses, if_p);
+ block = begin_omp_parallel ();
+ save = cp_parser_begin_omp_structured_block (parser);
+ tree ret = cp_parser_omp_loop (parser, pragma_tok, p_name, mask,
+ cclauses, if_p);
+ cp_parser_end_omp_structured_block (parser, save);
+ stmt = finish_omp_parallel (cclauses[C_OMP_CLAUSE_SPLIT_PARALLEL],
+ block);
+ if (ret == NULL_TREE)
+ return ret;
+ OMP_PARALLEL_COMBINED (stmt) = 1;
+ return stmt;
+ }
else if (!flag_openmp) /* flag_openmp_simd */
{
cp_parser_skip_to_pragma_eol (parser, pragma_tok);
return NULL_TREE;
}
- else if (strcmp (p, "sections") == 0)
+ else if (cclauses == NULL && strcmp (p, "sections") == 0)
{
tree cclauses_buf[C_OMP_CLAUSE_SPLIT_COUNT];
cclauses = cclauses_buf;
SET_EXPR_LOCATION (ret, loc);
return add_stmt (ret);
}
+ else if (strcmp (p, "loop") == 0)
+ {
+ tree cclauses_buf[C_OMP_CLAUSE_SPLIT_COUNT];
+ if (cclauses == NULL)
+ cclauses = cclauses_buf;
+
+ cp_lexer_consume_token (parser->lexer);
+ if (!flag_openmp) /* flag_openmp_simd */
+ return cp_parser_omp_loop (parser, pragma_tok, p_name, mask,
+ cclauses, if_p);
+ keep_next_level (true);
+ sb = begin_omp_structured_block ();
+ save = cp_parser_begin_omp_structured_block (parser);
+ ret = cp_parser_omp_loop (parser, pragma_tok, p_name, mask,
+ cclauses, if_p);
+ cp_parser_end_omp_structured_block (parser, save);
+ tree body = finish_omp_structured_block (sb);
+ if (ret == NULL)
+ return ret;
+ clauses = cclauses[C_OMP_CLAUSE_SPLIT_TEAMS];
+ ret = make_node (OMP_TEAMS);
+ TREE_TYPE (ret) = void_type_node;
+ OMP_TEAMS_CLAUSES (ret) = clauses;
+ OMP_TEAMS_BODY (ret) = body;
+ OMP_TEAMS_COMBINED (ret) = 1;
+ SET_EXPR_LOCATION (ret, loc);
+ return add_stmt (ret);
+ }
}
if (!flag_openmp) /* flag_openmp_simd */
{
( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEVICE) \
| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_MAP) \
| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_IF) \
- | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_USE_DEVICE_PTR))
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_USE_DEVICE_PTR) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_USE_DEVICE_ADDR))
static tree
cp_parser_omp_target_data (cp_parser *parser, cp_token *pragma_tok, bool *if_p)
*pc = OMP_CLAUSE_CHAIN (*pc);
continue;
}
- else if (OMP_CLAUSE_CODE (*pc) == OMP_CLAUSE_USE_DEVICE_PTR)
+ else if (OMP_CLAUSE_CODE (*pc) == OMP_CLAUSE_USE_DEVICE_PTR
+ || OMP_CLAUSE_CODE (*pc) == OMP_CLAUSE_USE_DEVICE_ADDR)
map_seen = 3;
pc = &OMP_CLAUSE_CHAIN (*pc);
}
if (map_seen == 0)
error_at (pragma_tok->location,
"%<#pragma omp target data%> must contain at least "
- "one %<map%> or %<use_device_ptr%> clause");
+ "one %<map%>, %<use_device_ptr%> or %<use_device_addr%> "
+ "clause");
return NULL_TREE;
}
#define OMP_DECLARE_TARGET_CLAUSE_MASK \
( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_TO) \
- | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_LINK))
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_LINK) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEVICE_TYPE))
static void
cp_parser_omp_declare_target (cp_parser *parser, cp_token *pragma_tok)
{
tree clauses = NULL_TREE;
+ int device_type = 0;
+ bool only_device_type = true;
if (cp_lexer_next_token_is (parser->lexer, CPP_NAME))
clauses
= cp_parser_omp_all_clauses (parser, OMP_DECLARE_TARGET_CLAUSE_MASK,
scope_chain->omp_declare_target_attribute++;
return;
}
- if (scope_chain->omp_declare_target_attribute)
- error_at (pragma_tok->location,
- "%<#pragma omp declare target%> with clauses in between "
- "%<#pragma omp declare target%> without clauses and "
- "%<#pragma omp end declare target%>");
+ for (tree c = clauses; c; c = OMP_CLAUSE_CHAIN (c))
+ if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_DEVICE_TYPE)
+ device_type |= OMP_CLAUSE_DEVICE_TYPE_KIND (c);
for (tree c = clauses; c; c = OMP_CLAUSE_CHAIN (c))
{
+ if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_DEVICE_TYPE)
+ continue;
tree t = OMP_CLAUSE_DECL (c), id;
tree at1 = lookup_attribute ("omp declare target", DECL_ATTRIBUTES (t));
tree at2 = lookup_attribute ("omp declare target link",
DECL_ATTRIBUTES (t));
+ only_device_type = false;
if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_LINK)
{
id = get_identifier ("omp declare target link");
}
}
}
+ if (TREE_CODE (t) != FUNCTION_DECL)
+ continue;
+ if ((device_type & OMP_CLAUSE_DEVICE_TYPE_HOST) != 0)
+ {
+ tree at3 = lookup_attribute ("omp declare target host",
+ DECL_ATTRIBUTES (t));
+ if (at3 == NULL_TREE)
+ {
+ id = get_identifier ("omp declare target host");
+ DECL_ATTRIBUTES (t)
+ = tree_cons (id, NULL_TREE, DECL_ATTRIBUTES (t));
+ }
+ }
+ if ((device_type & OMP_CLAUSE_DEVICE_TYPE_NOHOST) != 0)
+ {
+ tree at3 = lookup_attribute ("omp declare target nohost",
+ DECL_ATTRIBUTES (t));
+ if (at3 == NULL_TREE)
+ {
+ id = get_identifier ("omp declare target nohost");
+ DECL_ATTRIBUTES (t)
+ = tree_cons (id, NULL_TREE, DECL_ATTRIBUTES (t));
+ }
+ }
}
+ if (device_type && only_device_type)
+ warning_at (OMP_CLAUSE_LOCATION (clauses), 0,
+ "directive with only %<device_type%> clauses ignored");
}
static void
cp_token_cache *cp;
int errs;
void *p;
-
+
/* Get the high-water mark for the DECLARATOR_OBSTACK. */
p = obstack_alloc (&declarator_obstack, 0);
|| id_equal (orig_reduc_id, "max")))))
error_at (loc, "predeclared arithmetic type %qT in "
"%<#pragma omp declare reduction%>", type);
- else if (TREE_CODE (type) == FUNCTION_TYPE
- || TREE_CODE (type) == METHOD_TYPE
+ else if (FUNC_OR_METHOD_TYPE_P (type)
|| TREE_CODE (type) == ARRAY_TYPE)
error_at (loc, "function or array type %qT in "
"%<#pragma omp declare reduction%>", type);
error_at (loc, "reference type %qT in "
"%<#pragma omp declare reduction%>", type);
else if (TYPE_QUALS_NO_ADDR_SPACE (type))
- error_at (loc, "const, volatile or __restrict qualified type %qT in "
- "%<#pragma omp declare reduction%>", type);
+ error_at (loc, "%<const%>, %<volatile%> or %<__restrict%>-qualified "
+ "type %qT in %<#pragma omp declare reduction%>", type);
else
types.safe_push (type);
= cp_parser_oacc_all_clauses (parser, OACC_ROUTINE_CLAUSE_MASK,
"#pragma acc routine",
cp_lexer_peek_token (parser->lexer));
+ /* The clauses are in reverse order; fix that to make later diagnostic
+ emission easier. */
+ data.clauses = nreverse (data.clauses);
if (decl && is_overloaded_fn (decl)
&& (TREE_CODE (decl) != FUNCTION_DECL
parser->oacc_routine->clauses
= cp_parser_oacc_all_clauses (parser, OACC_ROUTINE_CLAUSE_MASK,
"#pragma acc routine", pragma_tok);
+ /* The clauses are in reverse order; fix that to make later diagnostic
+ emission easier. */
+ parser->oacc_routine->clauses = nreverse (parser->oacc_routine->clauses);
cp_parser_pop_lexer (parser);
/* Later, cp_finalize_oacc_routine will process the clauses, and then set
fndecl_seen. */
return;
}
- if (oacc_get_fn_attrib (fndecl))
+ int compatible
+ = oacc_verify_routine_clauses (fndecl, &parser->oacc_routine->clauses,
+ parser->oacc_routine->loc,
+ "#pragma acc routine");
+ if (compatible < 0)
{
- error_at (parser->oacc_routine->loc,
- "%<#pragma acc routine%> already applied to %qD", fndecl);
parser->oacc_routine = NULL;
return;
}
-
- if (TREE_USED (fndecl) || (!is_defn && DECL_SAVED_TREE (fndecl)))
+ if (compatible > 0)
{
- error_at (parser->oacc_routine->loc,
- TREE_USED (fndecl)
- ? G_("%<#pragma acc routine%> must be applied before use")
- : G_("%<#pragma acc routine%> must be applied before "
- "definition"));
- parser->oacc_routine = NULL;
- return;
}
+ else
+ {
+ if (TREE_USED (fndecl) || (!is_defn && DECL_SAVED_TREE (fndecl)))
+ {
+ error_at (parser->oacc_routine->loc,
+ TREE_USED (fndecl)
+ ? G_("%<#pragma acc routine%> must be applied before"
+ " use")
+ : G_("%<#pragma acc routine%> must be applied before"
+ " definition"));
+ parser->oacc_routine = NULL;
+ return;
+ }
- /* Process the routine's dimension clauses. */
- tree dims = oacc_build_routine_dims (parser->oacc_routine->clauses);
- oacc_replace_fn_attrib (fndecl, dims);
+ /* Set the routine's level of parallelism. */
+ tree dims = oacc_build_routine_dims (parser->oacc_routine->clauses);
+ oacc_replace_fn_attrib (fndecl, dims);
- /* Add an "omp declare target" attribute. */
- DECL_ATTRIBUTES (fndecl)
- = tree_cons (get_identifier ("omp declare target"),
- NULL_TREE, DECL_ATTRIBUTES (fndecl));
+ /* Add an "omp declare target" attribute. */
+ DECL_ATTRIBUTES (fndecl)
+ = tree_cons (get_identifier ("omp declare target"),
+ parser->oacc_routine->clauses,
+ DECL_ATTRIBUTES (fndecl));
+ }
/* Don't unset parser->oacc_routine here: we may still need it to
diagnose wrong usage. But, remember that we've used this "#pragma acc
stmt = cp_parser_omp_for (parser, pragma_tok, p_name, mask, NULL,
if_p);
break;
+ case PRAGMA_OMP_LOOP:
+ strcpy (p_name, "#pragma omp");
+ stmt = cp_parser_omp_loop (parser, pragma_tok, p_name, mask, NULL,
+ if_p);
+ break;
case PRAGMA_OMP_MASTER:
strcpy (p_name, "#pragma omp");
stmt = cp_parser_omp_master (parser, pragma_tok, p_name, mask, NULL,
else if (keyword == RID_ATOMIC_CANCEL)
{
/* cancel-and-throw is unimplemented. */
- sorry ("atomic_cancel");
+ sorry ("%<atomic_cancel%>");
noex = NULL_TREE;
}
else
- noex = cp_parser_noexcept_specification_opt (parser, true, NULL, true);
+ noex = cp_parser_noexcept_specification_opt (parser,
+ CP_PARSER_FLAGS_NONE,
+ /*require_constexpr=*/true,
+ /*consumed_expr=*/NULL,
+ /*return_cond=*/true);
/* Keep track if we're in the lexical scope of an outer transaction. */
new_in = this_in | (old_in & TM_STMT_ATTR_OUTER);
parser->in_transaction = this_in;
/* Parse a noexcept specification. */
- noex = cp_parser_noexcept_specification_opt (parser, false, &noex_expr,
- true);
+ noex = cp_parser_noexcept_specification_opt (parser,
+ CP_PARSER_FLAGS_NONE,
+ /*require_constexpr=*/false,
+ &noex_expr,
+ /*return_cond=*/true);
if (!noex || !noex_expr
|| cp_lexer_peek_token (parser->lexer)->type == CPP_OPEN_PAREN)
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)
case PRAGMA_OMP_CRITICAL:
case PRAGMA_OMP_DISTRIBUTE:
case PRAGMA_OMP_FOR:
+ case PRAGMA_OMP_LOOP:
case PRAGMA_OMP_MASTER:
case PRAGMA_OMP_PARALLEL:
case PRAGMA_OMP_SECTIONS:
cp_parser_omp_end_declare_target (parser, pragma_tok);
return false;
+ case PRAGMA_OMP_SCAN:
+ error_at (pragma_tok->location,
+ "%<#pragma omp scan%> may only be used in "
+ "a loop construct with %<inscan%> %<reduction%> clause");
+ break;
+
case PRAGMA_OMP_SECTION:
- error_at (pragma_tok->location,
+ error_at (pragma_tok->location,
"%<#pragma omp section%> may only be used in "
"%<#pragma omp sections%> construct");
break;
non_type = true;
}
- // Attach the constraint to the parm before processing.
+ /* Attach the constraint to the parm before processing. */
tree node = build_tree_list (NULL_TREE, synth_tmpl_parm);
TREE_TYPE (node) = constr;
tree new_parm
TREE_VEC_ELT (new_parms, new_parm_idx) = parser->implicit_template_parms;
}
- // If the new parameter was constrained, we need to add that to the
- // constraints in the template parameter list.
+ /* If the new parameter was constrained, we need to add that to the
+ constraints in the template parameter list. */
if (tree req = TEMPLATE_PARM_CONSTRAINTS (tree_last (new_parm)))
{
tree reqs = TEMPLATE_PARMS_CONSTRAINTS (current_template_parms);