/* -*- C++ -*- Parser.
- Copyright (C) 2000-2018 Free Software Foundation, Inc.
+ Copyright (C) 2000-2019 Free Software Foundation, Inc.
Written by Mark Mitchell <mark@codesourcery.com>.
This file is part of GCC.
#include "context.h"
#include "gcc-rich-location.h"
#include "tree-iterator.h"
-#include "c-family/name-hint.h"
+#include "cp-name-hint.h"
+#include "memmodel.h"
\f
/* The lexer. */
parser->allow_non_integral_constant_expression_p);
cp_debug_print_flag (file, "Seen non-constant expression",
parser->non_integral_constant_expression_p);
- cp_debug_print_flag (file, "Local names and 'this' forbidden in "
- "current context",
- parser->local_variables_forbidden_p);
+ cp_debug_print_flag (file, "Local names forbidden in current context",
+ (parser->local_variables_forbidden_p
+ & LOCAL_VARS_FORBIDDEN));
+ cp_debug_print_flag (file, "'this' forbidden in current context",
+ (parser->local_variables_forbidden_p
+ & THIS_FORBIDDEN));
cp_debug_print_flag (file, "In unbraced linkage specification",
parser->in_unbraced_linkage_specification_p);
cp_debug_print_flag (file, "Parsing a declarator",
parser->in_statement & IN_IF_STMT);
cp_debug_print_flag (file, "Parsing a type-id in an expression "
"context", parser->in_type_id_in_expr_p);
- cp_debug_print_flag (file, "Declarations are implicitly extern \"C\"",
- parser->implicit_extern_c);
cp_debug_print_flag (file, "String expressions should be translated "
"to execution character set",
parser->translate_strings_p);
return cp_lexer_peek_nth_token (lexer, n)->keyword == keyword;
}
-/* Return true if the next token is not the indicated KEYWORD. */
-
-static inline bool
-cp_lexer_next_token_is_not_keyword (cp_lexer* lexer, enum rid keyword)
-{
- return cp_lexer_peek_token (lexer)->keyword != keyword;
-}
-
/* Return true if KEYWORD can start a decl-specifier. */
bool
case RID_TYPENAME:
/* Simple type specifiers. */
case RID_CHAR:
+ case RID_CHAR8:
case RID_CHAR16:
case RID_CHAR32:
case RID_WCHAR:
static cp_declarator *
make_id_declarator (tree qualifying_scope, tree unqualified_name,
- special_function_kind sfk)
+ special_function_kind sfk, location_t id_location)
{
cp_declarator *declarator;
declarator->u.id.qualifying_scope = qualifying_scope;
declarator->u.id.unqualified_name = unqualified_name;
declarator->u.id.sfk = sfk;
-
+ declarator->id_loc = id_location;
+
return declarator;
}
/* Search for a declarator name, or any other declarator that goes
after the point where the ellipsis could appear in a parameter
- pack. If we find any of these, then this declarator can not be
+ pack. If we find any of these, then this declarator cannot be
made into a parameter pack. */
bool found = false;
while (declarator && !found)
constexpr. */
CP_PARSER_FLAGS_ONLY_TYPE_OR_CONSTEXPR = 0x8,
/* When parsing a decl-specifier-seq, only allow mutable or constexpr. */
- CP_PARSER_FLAGS_ONLY_MUTABLE_OR_CONSTEXPR = 0x10
+ CP_PARSER_FLAGS_ONLY_MUTABLE_OR_CONSTEXPR = 0x10,
+ /* When parsing a decl-specifier-seq, allow missing typename. */
+ CP_PARSER_FLAGS_TYPENAME_OPTIONAL = 0x20
};
/* This type is used for parameters and variables which hold
/* Basic concepts [gram.basic] */
-static bool cp_parser_translation_unit
- (cp_parser *);
+static void cp_parser_translation_unit (cp_parser *);
/* Expressions [gram.expr] */
(cp_parser *, cp_id_kind * = NULL, bool = false, bool = false, bool = false);
static enum tree_code cp_parser_unary_operator
(cp_token *);
+static tree cp_parser_has_attribute_expression
+ (cp_parser *);
static tree cp_parser_new_expression
(cp_parser *);
static vec<tree, va_gc> *cp_parser_new_placement
static tree cp_parser_c_for
(cp_parser *, tree, tree, bool, unsigned short);
static tree cp_parser_range_for
- (cp_parser *, tree, tree, tree, bool, unsigned short);
+ (cp_parser *, tree, tree, tree, bool, unsigned short, bool);
static void do_range_for_auto_deduction
(tree, tree);
static tree cp_parser_perform_range_for_lookup
(cp_parser *);
static void cp_parser_declaration
(cp_parser *);
+static void cp_parser_toplevel_declaration
+ (cp_parser *);
static void cp_parser_block_declaration
(cp_parser *, bool);
static void cp_parser_simple_declaration
(cp_parser *, cp_decl_specifier_seq *, cp_parser_flags);
static tree cp_parser_type_name
(cp_parser *, bool);
-static tree cp_parser_type_name
- (cp_parser *);
static tree cp_parser_nonclass_name
(cp_parser* parser);
static tree cp_parser_elaborated_type_specifier
/* Declarators [gram.dcl.decl] */
static tree cp_parser_init_declarator
- (cp_parser *, cp_decl_specifier_seq *, vec<deferred_access_check, va_gc> *,
- bool, bool, int, bool *, tree *, location_t *, tree *);
+ (cp_parser *, cp_parser_flags, cp_decl_specifier_seq *,
+ vec<deferred_access_check, va_gc> *, bool, bool, int, bool *, tree *,
+ location_t *, tree *);
static cp_declarator *cp_parser_declarator
- (cp_parser *, cp_parser_declarator_kind, int *, bool *, bool, bool);
+ (cp_parser *, cp_parser_declarator_kind, cp_parser_flags, int *, bool *,
+ bool, bool, bool);
static cp_declarator *cp_parser_direct_declarator
- (cp_parser *, cp_parser_declarator_kind, int *, bool, bool);
+ (cp_parser *, cp_parser_declarator_kind, cp_parser_flags, int *, bool, bool,
+ bool);
static enum tree_code cp_parser_ptr_operator
(cp_parser *, tree *, cp_cv_quals *, tree *);
static cp_cv_quals cp_parser_cv_qualifier_seq_opt
static tree cp_parser_declarator_id
(cp_parser *, bool);
static tree cp_parser_type_id
- (cp_parser *);
+ (cp_parser *, cp_parser_flags = CP_PARSER_FLAGS_NONE, location_t * = NULL);
static tree cp_parser_template_type_arg
(cp_parser *);
static tree cp_parser_trailing_type_id (cp_parser *);
static tree cp_parser_type_id_1
- (cp_parser *, bool, bool);
+ (cp_parser *, cp_parser_flags, bool, bool, location_t *);
static void cp_parser_type_specifier_seq
- (cp_parser *, bool, bool, cp_decl_specifier_seq *);
+ (cp_parser *, cp_parser_flags, bool, bool, cp_decl_specifier_seq *);
static tree cp_parser_parameter_declaration_clause
- (cp_parser *);
+ (cp_parser *, cp_parser_flags);
static tree cp_parser_parameter_declaration_list
- (cp_parser *);
+ (cp_parser *, cp_parser_flags);
static cp_parameter_declarator *cp_parser_parameter_declaration
- (cp_parser *, bool, bool *);
+ (cp_parser *, cp_parser_flags, bool, bool *);
static tree cp_parser_default_argument
(cp_parser *, bool);
static void cp_parser_function_body
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 cp_expr cp_parser_operator_function_id
(cp_parser *);
static cp_expr cp_parser_operator
- (cp_parser *);
+ (cp_parser *, location_t);
/* Templates [gram.temp] */
static tree cp_parser_gnu_attributes_opt
(cp_parser *);
static tree cp_parser_gnu_attribute_list
- (cp_parser *);
+ (cp_parser *, bool = false);
static tree cp_parser_std_attribute
(cp_parser *, tree);
static tree cp_parser_std_attribute_spec
if (cp_lexer_peek_conflict_marker (parser->lexer, token->type, &loc))
{
error_at (loc, "version control conflict marker in file");
+ expanded_location token_exploc = expand_location (token->location);
+ /* Consume tokens until the end of the source line. */
+ while (1)
+ {
+ cp_lexer_consume_token (parser->lexer);
+ cp_token *next = cp_lexer_peek_token (parser->lexer);
+ if (next == NULL)
+ break;
+ expanded_location next_exploc = expand_location (next->location);
+ if (next_exploc.file != token_exploc.file)
+ break;
+ if (next_exploc.line != token_exploc.line)
+ break;
+ }
return;
}
}
to specify an argument list. Emit a useful error message. */
if (DECL_TYPE_TEMPLATE_P (decl))
{
+ auto_diagnostic_group d;
error_at (location,
"invalid use of template-name %qE without an argument list",
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)
else if (!parser->scope)
{
/* Issue an error message. */
+ auto_diagnostic_group d;
name_hint hint;
if (TREE_CODE (id) == IDENTIFIER_NODE)
hint = lookup_name_fuzzy (id, FUZZY_LOOKUP_TYPENAME, location);
- if (hint)
+ if (const char *suggestion = hint.suggestion ())
{
gcc_rich_location richloc (location);
- richloc.add_fixit_replace (hint.suggestion ());
+ richloc.add_fixit_replace (suggestion);
error_at (&richloc,
"%qE does not name a type; did you mean %qs?",
- id, hint.suggestion ());
+ id, suggestion);
}
else
error_at (location, "%qE does not name a type", id);
The user should have said "typename A<T>::X". */
if (cxx_dialect < cxx11 && id == ridpointers[(int)RID_CONSTEXPR])
inform (location, "C++11 %<constexpr%> only available with "
- "-std=c++11 or -std=gnu++11");
+ "%<-std=c++11%> or %<-std=gnu++11%>");
else if (cxx_dialect < cxx11 && id == ridpointers[(int)RID_NOEXCEPT])
inform (location, "C++11 %<noexcept%> only available with "
- "-std=c++11 or -std=gnu++11");
+ "%<-std=c++11%> or %<-std=gnu++11%>");
else if (cxx_dialect < cxx11
&& TREE_CODE (id) == IDENTIFIER_NODE
&& id_equal (id, "thread_local"))
inform (location, "C++11 %<thread_local%> only available with "
- "-std=c++11 or -std=gnu++11");
+ "%<-std=c++11%> or %<-std=gnu++11%>");
else if (!flag_concepts && id == ridpointers[(int)RID_CONCEPT])
- inform (location, "%<concept%> only available with -fconcepts");
+ inform (location, "%<concept%> only available with %<-fconcepts%>");
else if (processing_template_decl && current_class_type
&& TYPE_BINFO (current_class_type))
{
{
if (TREE_CODE (parser->scope) == NAMESPACE_DECL)
{
+ auto_diagnostic_group d;
+ name_hint hint;
+ if (decl == error_mark_node)
+ hint = suggest_alternative_in_explicit_scope (location, id,
+ parser->scope);
+ const char *suggestion = hint.suggestion ();
+ gcc_rich_location richloc (location_of (id));
+ if (suggestion)
+ richloc.add_fixit_replace (suggestion);
if (cp_lexer_next_token_is (parser->lexer, CPP_LESS))
- error_at (location_of (id),
- "%qE in namespace %qE does not name a template type",
- id, parser->scope);
+ {
+ if (suggestion)
+ error_at (&richloc,
+ "%qE in namespace %qE does not name a template"
+ " type; did you mean %qs?",
+ id, parser->scope, suggestion);
+ else
+ error_at (&richloc,
+ "%qE in namespace %qE does not name a template type",
+ id, parser->scope);
+ }
else if (TREE_CODE (id) == TEMPLATE_ID_EXPR)
- error_at (location_of (id),
- "%qE in namespace %qE does not name a template type",
- TREE_OPERAND (id, 0), parser->scope);
+ {
+ if (suggestion)
+ error_at (&richloc,
+ "%qE in namespace %qE does not name a template"
+ " type; did you mean %qs?",
+ TREE_OPERAND (id, 0), parser->scope, suggestion);
+ else
+ error_at (&richloc,
+ "%qE in namespace %qE does not name a template"
+ " type",
+ TREE_OPERAND (id, 0), parser->scope);
+ }
else
- error_at (location_of (id),
- "%qE in namespace %qE does not name a type",
- id, parser->scope);
+ {
+ if (suggestion)
+ error_at (&richloc,
+ "%qE in namespace %qE does not name a type"
+ "; did you mean %qs?",
+ id, parser->scope, suggestion);
+ else
+ error_at (&richloc,
+ "%qE in namespace %qE does not name a type",
+ id, parser->scope);
+ }
if (DECL_P (decl))
inform (DECL_SOURCE_LOCATION (decl), "%qD declared here", decl);
- else if (decl == error_mark_node)
- suggest_alternative_in_explicit_scope (location, id,
- parser->scope);
}
else if (CLASS_TYPE_P (parser->scope)
&& constructor_name_p (id, parser->scope))
{
/* A<T>::A<T>() */
+ auto_diagnostic_group d;
error_at (location, "%<%T::%E%> names the constructor, not"
" the type", parser->scope, id);
if (cp_lexer_next_token_is (parser->lexer, CPP_LESS))
else if (TYPE_P (parser->scope)
&& dependent_scope_p (parser->scope))
{
+ gcc_rich_location richloc (location);
+ richloc.add_fixit_insert_before ("typename ");
if (TREE_CODE (parser->scope) == TYPENAME_TYPE)
- error_at (location,
+ error_at (&richloc,
"need %<typename%> before %<%T::%D::%E%> because "
"%<%T::%D%> is a dependent scope",
TYPE_CONTEXT (parser->scope),
TYPE_CONTEXT (parser->scope),
TYPENAME_TYPE_FULLNAME (parser->scope));
else
- error_at (location, "need %<typename%> before %<%T::%E%> because "
+ error_at (&richloc, "need %<typename%> before %<%T::%E%> because "
"%qT is a dependent scope",
parser->scope, id, parser->scope);
}
else if (TYPE_P (parser->scope))
{
+ auto_diagnostic_group d;
if (!COMPLETE_TYPE_P (parser->scope))
cxx_incomplete_type_error (location_of (id), NULL_TREE,
parser->scope);
switch (token->type)
{
- case CPP_EOF:
case CPP_PRAGMA_EOL:
+ if (!parser->lexer->in_pragma)
+ break;
+ /* FALLTHRU */
+ case CPP_EOF:
/* If we've run out of tokens, then there is no closing `)'. */
return 0;
switch (token->type)
{
- case CPP_EOF:
case CPP_PRAGMA_EOL:
+ if (!parser->lexer->in_pragma)
+ break;
+ /* FALLTHRU */
+ case CPP_EOF:
/* If we've run out of tokens, stop. */
return;
switch (token->type)
{
- case CPP_EOF:
case CPP_PRAGMA_EOL:
+ if (!parser->lexer->in_pragma)
+ break;
+ /* FALLTHRU */
+ case CPP_EOF:
/* If we've run out of tokens, stop. */
return;
switch (token->type)
{
- case CPP_EOF:
case CPP_PRAGMA_EOL:
+ if (!parser->lexer->in_pragma)
+ break;
+ /* FALLTHRU */
+ case CPP_EOF:
/* If we've run out of tokens, stop. */
return false;
parser->non_integral_constant_expression_p = false;
/* Local variable names are not forbidden. */
- parser->local_variables_forbidden_p = false;
+ parser->local_variables_forbidden_p = 0;
/* We are not processing an `extern "C"' declaration. */
parser->in_unbraced_linkage_specification_p = false;
/* We are not parsing a type-id inside an expression. */
parser->in_type_id_in_expr_p = false;
- /* Declarations aren't implicitly extern "C". */
- parser->implicit_extern_c = false;
-
/* String literals should be translated to the execution character set. */
parser->translate_strings_p = true;
tree value;
size_t count;
struct obstack str_ob;
+ struct obstack loc_ob;
cpp_string str, istr, *strs;
cp_token *tok;
enum cpp_ttype type, curr_type;
{
location_t last_tok_loc = tok->location;
gcc_obstack_init (&str_ob);
+ gcc_obstack_init (&loc_ob);
count = 0;
do
else if (curr_type != CPP_STRING)
{
rich_location rich_loc (line_table, tok->location);
- rich_loc.add_range (last_tok_loc, false);
+ rich_loc.add_range (last_tok_loc);
error_at (&rich_loc,
"unsupported non-standard concatenation "
"of string literals");
}
obstack_grow (&str_ob, &str, sizeof (cpp_string));
+ obstack_grow (&loc_ob, &tok->location, sizeof (location_t));
last_tok_loc = tok->location;
{
value = build_string (istr.len, (const char *)istr.text);
free (CONST_CAST (unsigned char *, istr.text));
+ if (count > 1)
+ {
+ location_t *locs = (location_t *)obstack_finish (&loc_ob);
+ gcc_assert (g_string_concat_db);
+ g_string_concat_db->record_string_concatenation (count, locs);
+ }
switch (type)
{
default:
case CPP_STRING:
- case CPP_UTF8STRING:
TREE_TYPE (value) = char_array_type_node;
break;
+ case CPP_UTF8STRING:
+ if (flag_char8_t)
+ TREE_TYPE (value) = char8_array_type_node;
+ else
+ TREE_TYPE (value) = char_array_type_node;
+ break;
case CPP_STRING16:
TREE_TYPE (value) = char16_array_type_node;
break;
value = error_mark_node;
if (count > 1)
- obstack_free (&str_ob, 0);
+ {
+ obstack_free (&str_ob, 0);
+ obstack_free (&loc_ob, 0);
+ }
return cp_expr (value, loc);
}
static tree
lookup_literal_operator (tree name, vec<tree, va_gc> *args)
{
- tree decl;
- decl = lookup_name (name);
+ tree decl = lookup_name (name);
if (!decl || !is_overloaded_fn (decl))
return error_mark_node;
for (lkp_iterator iter (decl); iter; ++iter)
{
- unsigned int ix;
- bool found = true;
tree fn = *iter;
- tree parmtypes = TYPE_ARG_TYPES (TREE_TYPE (fn));
- if (parmtypes != NULL_TREE)
+
+ if (tree parmtypes = TYPE_ARG_TYPES (TREE_TYPE (fn)))
{
- for (ix = 0; ix < vec_safe_length (args) && parmtypes != NULL_TREE;
+ unsigned int ix;
+ bool found = true;
+
+ for (ix = 0;
+ found && ix < vec_safe_length (args) && parmtypes != NULL_TREE;
++ix, parmtypes = TREE_CHAIN (parmtypes))
{
tree tparm = TREE_VALUE (parmtypes);
TREE_TYPE (targ))))
found = false;
}
+
if (found
&& ix == vec_safe_length (args)
/* May be this should be sufficient_parms_p instead,
/* Fill in CHARVEC with all of the parameters. */
charvec = make_tree_vec (len);
for (i = 0; i < len; ++i)
- TREE_VEC_ELT (charvec, i) = build_int_cst (char_type_node, str[i]);
+ {
+ unsigned char s[3] = { '\'', str[i], '\'' };
+ cpp_string in = { 3, s };
+ cpp_string out = { 0, 0 };
+ if (!cpp_interpret_string (parse_in, &in, 1, &out, CPP_STRING))
+ return NULL_TREE;
+ gcc_assert (out.len == 2);
+ TREE_VEC_ELT (charvec, i) = build_int_cst (char_type_node,
+ out.text[0]);
+ }
/* Build the argument packs. */
SET_ARGUMENT_PACK_ARGS (argpack, charvec);
if (decl && decl != error_mark_node)
{
tree tmpl_args = make_char_string_pack (num_string);
+ if (tmpl_args == NULL_TREE)
+ {
+ error ("failed to translate literal to execution character set %qT",
+ num_string);
+ return error_mark_node;
+ }
decl = lookup_template_function (decl, tmpl_args);
result = finish_call_expr (decl, &args, false, true,
tf_warning_or_error);
"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)
tree value = USERDEF_LITERAL_VALUE (literal);
int len = TREE_STRING_LENGTH (value)
/ TREE_INT_CST_LOW (TYPE_SIZE_UNIT (TREE_TYPE (TREE_TYPE (value)))) - 1;
- tree decl, result;
- vec<tree, va_gc> *args;
+ tree decl;
/* Build up a call to the user-defined operator. */
/* Lookup the name we got back from the id-expression. */
- args = make_tree_vector ();
+ releasing_vec rargs;
+ vec<tree, va_gc> *&args = rargs.get_ref();
vec_safe_push (args, value);
vec_safe_push (args, build_int_cst (size_type_node, len));
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);
+ return finish_call_expr (decl, &args, false, true,
+ tf_warning_or_error);
- /* Look for a template function with typename parameter CharT
- and parameter pack CharT... Call the function with
- template parameter characters representing the string. */
- args = make_tree_vector ();
+ /* Look for a suitable template function, either (C++20) with a single
+ parameter of class type, or (N3599) with typename parameter CharT and
+ parameter pack CharT... */
+ args->truncate (0);
decl = lookup_literal_operator (name, args);
if (decl && decl != error_mark_node)
{
- tree tmpl_args = make_string_pack (value);
+ /* Use resolve_nondeduced_context to try to choose one form of template
+ or the other. */
+ tree tmpl_args = make_tree_vec (1);
+ TREE_VEC_ELT (tmpl_args, 0) = value;
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;
+ tree res = resolve_nondeduced_context (decl, tf_none);
+ if (DECL_P (res))
+ decl = res;
+ else
+ {
+ TREE_OPERAND (decl, 1) = make_string_pack (value);
+ res = resolve_nondeduced_context (decl, tf_none);
+ if (DECL_P (res))
+ decl = res;
+ }
+ if (!DECL_P (decl) && cxx_dialect > cxx17)
+ TREE_OPERAND (decl, 1) = tmpl_args;
+ return finish_call_expr (decl, &args, false, true,
+ tf_warning_or_error);
}
- release_tree_vector (args);
error ("unable to find string literal operator %qD with %qT, %qT arguments",
name, TREE_TYPE (value), size_type_node);
/* Parse a translation-unit.
translation-unit:
- declaration-seq [opt]
-
- Returns TRUE if all went well. */
+ declaration-seq [opt] */
-static bool
+static void
cp_parser_translation_unit (cp_parser* parser)
{
- /* The address of the first non-permanent object on the declarator
- obstack. */
- static void *declarator_obstack_base;
-
- bool success;
+ gcc_checking_assert (!cp_error_declarator);
+
+ /* Create the declarator obstack. */
+ gcc_obstack_init (&declarator_obstack);
+ /* Create the error declarator. */
+ cp_error_declarator = make_declarator (cdk_error);
+ /* Create the empty parameter list. */
+ no_parameters = make_parameter_declarator (NULL, NULL, NULL_TREE,
+ UNKNOWN_LOCATION);
+ /* Remember where the base of the declarator obstack lies. */
+ void *declarator_obstack_base = obstack_next_free (&declarator_obstack);
+
+ bool implicit_extern_c = false;
- /* Create the declarator obstack, if necessary. */
- if (!cp_error_declarator)
+ for (;;)
{
- gcc_obstack_init (&declarator_obstack);
- /* Create the error declarator. */
- cp_error_declarator = make_declarator (cdk_error);
- /* Create the empty parameter list. */
- no_parameters = make_parameter_declarator (NULL, NULL, NULL_TREE,
- UNKNOWN_LOCATION);
- /* Remember where the base of the declarator obstack lies. */
- declarator_obstack_base = obstack_next_free (&declarator_obstack);
- }
-
- cp_parser_declaration_seq_opt (parser);
+ 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
+ != cp_lexer_peek_token (parser->lexer)->implicit_extern_c)
+ {
+ implicit_extern_c = !implicit_extern_c;
+ if (implicit_extern_c)
+ push_lang_context (lang_name_c);
+ else
+ pop_lang_context ();
+ }
- /* If there are no tokens left then all went well. */
- if (cp_lexer_next_token_is (parser->lexer, CPP_EOF))
- {
- /* Get rid of the token array; we don't need it any more. */
- cp_lexer_destroy (parser->lexer);
- parser->lexer = NULL;
+ if (token->type == CPP_EOF)
+ break;
- /* This file might have been a context that's implicitly extern
- "C". If so, pop the lang context. (Only relevant for PCH.) */
- if (parser->implicit_extern_c)
+ if (token->type == CPP_CLOSE_BRACE)
{
- pop_lang_context ();
- parser->implicit_extern_c = false;
+ cp_parser_error (parser, "expected declaration");
+ cp_lexer_consume_token (parser->lexer);
+ /* If the next token is now a `;', consume it. */
+ if (cp_lexer_next_token_is (parser->lexer, CPP_SEMICOLON))
+ cp_lexer_consume_token (parser->lexer);
}
+ else
+ cp_parser_toplevel_declaration (parser);
+ }
- /* Finish up. */
- finish_translation_unit ();
+ /* Get rid of the token array; we don't need it any more. */
+ cp_lexer_destroy (parser->lexer);
+ parser->lexer = NULL;
- success = true;
- }
- else
- {
- cp_parser_error (parser, "expected declaration");
- success = false;
- }
+ /* The EOF should have reset this. */
+ gcc_checking_assert (!implicit_extern_c);
/* Make sure the declarator obstack was fully cleaned up. */
gcc_assert (obstack_next_free (&declarator_obstack)
== declarator_obstack_base);
-
- /* All went well. */
- return success;
}
/* Return the appropriate tsubst flags for parsing, possibly in N3276
if (!cast_p)
cp_parser_non_integral_constant_expression (parser, NIC_FLOAT);
}
- return cp_expr (token->u.value, token->location);
+ return (cp_expr (token->u.value, token->location)
+ .maybe_add_location_wrapper ());
case CPP_CHAR_USERDEF:
case CPP_CHAR16_USERDEF:
/* ??? Should wide strings be allowed when parser->translate_strings_p
is false (i.e. in attributes)? If not, we can kill the third
argument to cp_parser_string_literal. */
- return cp_parser_string_literal (parser,
- parser->translate_strings_p,
- true);
+ return (cp_parser_string_literal (parser,
+ parser->translate_strings_p,
+ true)
+ .maybe_add_location_wrapper ());
case CPP_OPEN_PAREN:
/* If we see `( { ' then we are looking at the beginning of
&& cxx_dialect < cxx17
&& !in_system_header_at (input_location))
pedwarn (input_location, 0, "fold-expressions only available "
- "with -std=c++17 or -std=gnu++17");
+ "with %<-std=c++17%> or %<-std=gnu++17%>");
}
else
/* Let the front end know that this expression was
/* Recognize the `this' keyword. */
case RID_THIS:
cp_lexer_consume_token (parser->lexer);
- if (parser->local_variables_forbidden_p)
+ if (parser->local_variables_forbidden_p & THIS_FORBIDDEN)
{
error_at (token->location,
"%<this%> may not be used in this context");
{
tree expression;
tree type;
- source_location type_location;
+ location_t type_location;
location_t start_loc
= cp_lexer_peek_token (parser->lexer)->location;
/* The `__builtin_va_arg' construct is used to handle
/*is_namespace=*/false,
/*check_dependency=*/true,
&ambiguous_decls,
- id_expr_token->location);
+ id_expression.get_location ());
/* If the lookup was ambiguous, an error will already have
been issued. */
if (ambiguous_decls)
template <int N> struct A {
int a[B<N>::i];
};
-
+
is accepted. At template-instantiation time, we
will check that B<N>::i is actually a constant. */
return decl;
}
/* Check to see if DECL is a local variable in a context
where that is forbidden. */
- if (parser->local_variables_forbidden_p
+ if ((parser->local_variables_forbidden_p & LOCAL_VARS_FORBIDDEN)
&& local_variable_p (decl))
{
- error_at (id_expr_token->location,
+ error_at (id_expression.get_location (),
"local variable %qD may not appear in this context",
decl.get_value ());
return error_mark_node;
id_expression.get_location ()));
if (error_msg)
cp_parser_error (parser, error_msg);
- decl.set_location (id_expr_token->location);
+ /* Build a location for an id-expression of the form:
+ ::ns::id
+ ~~~~~~^~
+ or:
+ id
+ ^~
+ i.e. from the start of the first token to the end of the final
+ token, with the caret at the start of the unqualified-id. */
+ location_t caret_loc = get_pure_location (id_expression.get_location ());
+ location_t start_loc = get_start (id_expr_token->location);
+ location_t finish_loc = get_finish (id_expression.get_location ());
+ location_t combined_loc
+ = make_location (caret_loc, start_loc, finish_loc);
+
+ decl.set_location (combined_loc);
return decl;
}
tree object_scope;
tree scope;
bool done;
+ location_t tilde_loc = token->location;
/* Consume the `~' token. */
cp_lexer_consume_token (parser->lexer);
}
gcc_assert (!scope || TYPE_P (scope));
+ token = cp_lexer_peek_token (parser->lexer);
+
+ /* Create a location with caret == start at the tilde,
+ finishing at the end of the peeked token, e.g:
+ ~token
+ ^~~~~~. */
+ location_t loc
+ = make_location (tilde_loc, tilde_loc, token->location);
+
/* If the name is of the form "X::~X" it's OK even if X is a
typedef. */
- token = cp_lexer_peek_token (parser->lexer);
+
if (scope
&& token->type == CPP_NAME
&& (cp_lexer_peek_nth_token (parser->lexer, 2)->type
&& constructor_name_p (token->u.value, scope))))
{
cp_lexer_consume_token (parser->lexer);
- return build_nt (BIT_NOT_EXPR, scope);
+ return cp_expr (build_nt (BIT_NOT_EXPR, scope), loc);
}
/* ~auto means the destructor of whatever the object is. */
if (cp_parser_is_keyword (token, RID_AUTO))
{
if (cxx_dialect < cxx14)
- pedwarn (input_location, 0,
+ pedwarn (loc, 0,
"%<~auto%> only available with "
- "-std=c++14 or -std=gnu++14");
+ "%<-std=c++14%> or %<-std=gnu++14%>");
cp_lexer_consume_token (parser->lexer);
- return build_nt (BIT_NOT_EXPR, make_auto ());
+ return cp_expr (build_nt (BIT_NOT_EXPR, make_auto (), loc));
}
/* If there was an explicit qualification (S::~T), first look
type_decl = cp_parser_identifier (parser);
if (type_decl != error_mark_node)
type_decl = build_nt (BIT_NOT_EXPR, type_decl);
- return type_decl;
+ return cp_expr (type_decl, loc);
}
}
/* If an error occurred, assume that the name of the
if (declarator_p && scope && !check_dtor_name (scope, type_decl))
{
if (!cp_parser_uncommitted_to_tentative_parse_p (parser))
- error_at (token->location,
+ error_at (loc,
"declaration of %<~%T%> as member of %qT",
type_decl, scope);
cp_parser_simulate_error (parser);
&& !DECL_IMPLICIT_TYPEDEF_P (type_decl)
&& !DECL_SELF_REFERENCE_P (type_decl)
&& !cp_parser_uncommitted_to_tentative_parse_p (parser))
- error_at (token->location,
+ error_at (loc,
"typedef-name %qD used as destructor declarator",
type_decl);
- return build_nt (BIT_NOT_EXPR, TREE_TYPE (type_decl));
+ return cp_expr (build_nt (BIT_NOT_EXPR, TREE_TYPE (type_decl), loc));
}
case CPP_KEYWORD:
/* Parse the type to which we are casting. */
saved_in_type_id_in_expr_p = parser->in_type_id_in_expr_p;
parser->in_type_id_in_expr_p = true;
- type = cp_parser_type_id (parser);
+ type = cp_parser_type_id (parser, CP_PARSER_FLAGS_TYPENAME_OPTIONAL,
+ NULL);
parser->in_type_id_in_expr_p = saved_in_type_id_in_expr_p;
/* Look for the closing `>'. */
cp_parser_require (parser, CPP_GREATER, RT_GREATER);
break;
}
+ case RID_BUILTIN_CONVERTVECTOR:
+ {
+ tree expression;
+ tree type;
+ /* Consume the `__builtin_convertvector' token. */
+ cp_lexer_consume_token (parser->lexer);
+ /* Look for the opening `('. */
+ matching_parens parens;
+ parens.require_open (parser);
+ /* Now, parse the assignment-expression. */
+ expression = cp_parser_assignment_expression (parser);
+ /* Look for the `,'. */
+ cp_parser_require (parser, CPP_COMMA, RT_COMMA);
+ location_t type_location
+ = cp_lexer_peek_token (parser->lexer)->location;
+ /* Parse the type-id. */
+ {
+ type_id_in_expr_sentinel s (parser);
+ type = cp_parser_type_id (parser);
+ }
+ /* Look for the closing `)'. */
+ parens.require_close (parser);
+ return cp_build_vec_convert (expression, type_location, type,
+ tf_warning_or_error);
+ }
+
default:
{
tree type;
is_member_access = false;
+ tree stripped_expression
+ = tree_strip_any_location_wrapper (postfix_expression);
is_builtin_constant_p
- = DECL_IS_BUILTIN_CONSTANT_P (postfix_expression);
+ = DECL_IS_BUILTIN_CONSTANT_P (stripped_expression);
if (is_builtin_constant_p)
{
/* The whole point of __builtin_constant_p is to allow
if (idk == CP_ID_KIND_UNQUALIFIED
|| idk == CP_ID_KIND_TEMPLATE_ID)
{
- if (identifier_p (postfix_expression))
+ if (identifier_p (postfix_expression)
+ /* In C++2A, we may need to perform ADL for a template
+ name. */
+ || (TREE_CODE (postfix_expression) == TEMPLATE_ID_EXPR
+ && identifier_p (TREE_OPERAND (postfix_expression, 0))))
{
if (!args->is_empty ())
{
else if (!args->is_empty ()
&& is_overloaded_fn (postfix_expression))
{
+ /* We only need to look at the first function,
+ because all the fns share the attribute we're
+ concerned with (all member fns or all local
+ fns). */
tree fn = get_first_fn (postfix_expression);
fn = STRIP_TEMPLATE (fn);
/* Do not do argument dependent lookup if regular
lookup finds a member function or a block-scope
function declaration. [basic.lookup.argdep]/3 */
- if (!DECL_FUNCTION_MEMBER_P (fn)
- && !DECL_LOCAL_FUNCTION_P (fn))
+ if (!((TREE_CODE (fn) == USING_DECL && DECL_DEPENDENT_P (fn))
+ || DECL_FUNCTION_MEMBER_P (fn)
+ || DECL_LOCAL_FUNCTION_P (fn)))
{
koenig_p = true;
if (!any_type_dependent_arguments_p (args))
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;
return ret_expr;
}
+ case RID_BUILTIN_HAS_ATTRIBUTE:
+ return cp_parser_has_attribute_expression (parser);
+
case RID_NEW:
return cp_parser_new_expression (parser);
case NEGATE_EXPR:
/* Immediately fold negation of a constant, unless the constant is 0
(since -0 == 0) or it would overflow. */
- if (unary_operator == NEGATE_EXPR && op_ttype == CPP_NUMBER
- && CONSTANT_CLASS_P (cast_expression)
- && !integer_zerop (cast_expression)
- && !TREE_OVERFLOW (cast_expression))
+ if (unary_operator == NEGATE_EXPR && op_ttype == CPP_NUMBER)
{
- tree folded = fold_build1 (unary_operator,
- TREE_TYPE (cast_expression),
- cast_expression);
- if (CONSTANT_CLASS_P (folded) && !TREE_OVERFLOW (folded))
+ tree stripped_expr
+ = tree_strip_any_location_wrapper (cast_expression);
+ if (CONSTANT_CLASS_P (stripped_expr)
+ && !integer_zerop (stripped_expr)
+ && !TREE_OVERFLOW (stripped_expr))
{
- expression = cp_expr (folded, loc);
- break;
+ tree folded = fold_build1 (unary_operator,
+ TREE_TYPE (stripped_expr),
+ stripped_expr);
+ if (CONSTANT_CLASS_P (folded) && !TREE_OVERFLOW (folded))
+ {
+ expression = maybe_wrap_with_location (folded, loc);
+ break;
+ }
}
}
/* Fall through. */
}
}
+/* Parse a __builtin_has_attribute([expr|type], attribute-spec) expression.
+ Returns a representation of the expression. */
+
+static tree
+cp_parser_has_attribute_expression (cp_parser *parser)
+{
+ location_t start_loc = cp_lexer_peek_token (parser->lexer)->location;
+
+ /* Consume the __builtin_has_attribute token. */
+ cp_lexer_consume_token (parser->lexer);
+
+ matching_parens parens;
+ if (!parens.require_open (parser))
+ return error_mark_node;
+
+ /* 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;
+
+ /* The restrictions on constant-expressions do not apply inside
+ sizeof expressions. */
+ bool saved_integral_constant_expression_p
+ = parser->integral_constant_expression_p;
+ bool saved_non_integral_constant_expression_p
+ = parser->non_integral_constant_expression_p;
+ parser->integral_constant_expression_p = false;
+
+ /* Do not actually evaluate the expression. */
+ ++cp_unevaluated_operand;
+ ++c_inhibit_evaluation_warnings;
+
+ tree oper = NULL_TREE;
+
+ /* We can't be sure yet whether we're looking at a type-id or an
+ expression. */
+ cp_parser_parse_tentatively (parser);
+
+ bool saved_in_type_id_in_expr_p = parser->in_type_id_in_expr_p;
+ parser->in_type_id_in_expr_p = true;
+ /* Look for the type-id. */
+ oper = cp_parser_type_id (parser);
+ parser->in_type_id_in_expr_p = saved_in_type_id_in_expr_p;
+
+ cp_parser_parse_definitely (parser);
+
+ /* If the type-id production did not work out, then we must be
+ looking at the unary-expression production. */
+ if (!oper || oper == error_mark_node)
+ oper = cp_parser_unary_expression (parser);
+
+ STRIP_ANY_LOCATION_WRAPPER (oper);
+
+ /* 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->integral_constant_expression_p
+ = saved_integral_constant_expression_p;
+ parser->non_integral_constant_expression_p
+ = saved_non_integral_constant_expression_p;
+
+ /* Consume the comma if it's there. */
+ if (!cp_parser_require (parser, CPP_COMMA, RT_COMMA))
+ {
+ cp_parser_skip_to_closing_parenthesis (parser, false, false,
+ /*consume_paren=*/true);
+ return error_mark_node;
+ }
+
+ /* Parse the attribute specification. */
+ bool ret = false;
+ location_t atloc = cp_lexer_peek_token (parser->lexer)->location;
+ if (tree attr = cp_parser_gnu_attribute_list (parser, /*exactly_one=*/true))
+ {
+ if (oper != error_mark_node)
+ {
+ /* Fold constant expressions used in attributes first. */
+ cp_check_const_attributes (attr);
+
+ /* Finally, see if OPER has been declared with ATTR. */
+ ret = has_attribute (atloc, oper, attr, default_conversion);
+ }
+
+ parens.require_close (parser);
+ }
+ else
+ {
+ error_at (atloc, "expected identifier");
+ cp_parser_skip_to_closing_parenthesis (parser, true, false, true);
+ }
+
+ /* Construct a location e.g. :
+ __builtin_has_attribute (oper, attr)
+ ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ 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);
+
+ cp_expr ret_expr (ret ? boolean_true_node : boolean_false_node);
+ ret_expr.set_location (compound_loc);
+ ret_expr = ret_expr.maybe_add_location_wrapper ();
+ return ret_expr;
+}
+
/* Parse a new-expression.
new-expression:
parser->type_definition_forbidden_message
= G_("types may not be defined in a new-type-id");
/* Parse the type-specifier-seq. */
- cp_parser_type_specifier_seq (parser, /*is_declaration=*/false,
+ cp_parser_type_specifier_seq (parser, CP_PARSER_FLAGS_TYPENAME_OPTIONAL,
+ /*is_declaration=*/false,
/*is_trailing_return=*/false,
&type_specifier_seq);
/* Restore the old message. */
|| (TREE_CODE (TREE_TYPE (TREE_OPERAND (current.lhs, 0)))
!= BOOLEAN_TYPE))))
/* Avoid warning for !!b == y where b is boolean. */
- && (!DECL_P (current.lhs)
+ && (!DECL_P (tree_strip_any_location_wrapper (current.lhs))
|| TREE_TYPE (current.lhs) == NULL_TREE
|| TREE_CODE (TREE_TYPE (current.lhs)) != BOOLEAN_TYPE))
warn_logical_not_parentheses (current.loc, current.tree_type,
}
else
{
- current.lhs = build_x_binary_op (combined_loc, current.tree_type,
+ op_location_t op_loc (current.loc, combined_loc);
+ current.lhs = build_x_binary_op (op_loc, current.tree_type,
current.lhs, current.lhs_type,
rhs, rhs_type, &overload,
complain_flags (decltype_p));
{
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;
}
LAMBDA_EXPR_LOCATION (lambda_expr) = token->location;
- if (cp_unevaluated_operand)
+ if (cxx_dialect >= cxx2a)
+ /* C++20 allows lambdas in unevaluated context. */;
+ else if (cp_unevaluated_operand)
{
if (!token->error_reported)
{
error_at (LAMBDA_EXPR_LOCATION (lambda_expr),
- "lambda-expression in unevaluated context");
+ "lambda-expression in unevaluated context"
+ " only available with %<-std=c++2a%> or %<-std=gnu++2a%>");
token->error_reported = true;
}
ok = false;
{
if (!token->error_reported)
{
- error_at (token->location, "lambda-expression in template-argument");
+ error_at (token->location, "lambda-expression in template-argument"
+ " only available with %<-std=c++2a%> or %<-std=gnu++2a%>");
token->error_reported = true;
}
ok = false;
push_deferring_access_checks (dk_no_deferred);
cp_parser_lambda_introducer (parser, lambda_expr);
+ if (cp_parser_error_occurred (parser))
+ return error_mark_node;
type = begin_lambda_type (lambda_expr);
if (type == error_mark_node)
/* By virtue of defining a local class, a lambda expression has access to
the private variables of enclosing classes. */
+ if (cp_parser_start_tentative_firewall (parser))
+ start = token;
+
ok &= cp_parser_lambda_declarator_opt (parser, lambda_expr);
if (ok && cp_parser_error_occurred (parser))
if (ok)
{
- if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_BRACE)
- && cp_parser_start_tentative_firewall (parser))
- start = token;
cp_parser_lambda_body (parser, lambda_expr);
}
else if (cp_parser_require (parser, CPP_OPEN_BRACE, RT_OPEN_BRACE))
/* And now that we're done, push proxies for an enclosing lambda. */
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);
+
if (ok)
lambda_expr = build_lambda_object (lambda_expr);
else
{
cp_lexer_consume_token (parser->lexer);
first = false;
+
+ if (!(at_function_scope_p () || parsing_nsdmi ()))
+ error ("non-local lambda expression cannot have a capture-default");
}
while (cp_lexer_next_token_is_not (parser->lexer, CPP_CLOSE_SQUARE))
location_t loc = cp_lexer_peek_token (parser->lexer)->location;
if (cxx_dialect < cxx17)
pedwarn (loc, 0, "%<*this%> capture only available with "
- "-std=c++17 or -std=gnu++17");
+ "%<-std=c++17%> or %<-std=gnu++17%>");
cp_lexer_consume_token (parser->lexer);
cp_lexer_consume_token (parser->lexer);
add_capture (lambda_expr,
continue;
}
+ bool init_pack_expansion = false;
+ if (cp_lexer_next_token_is (parser->lexer, CPP_ELLIPSIS))
+ {
+ location_t loc = cp_lexer_peek_token (parser->lexer)->location;
+ if (cxx_dialect < cxx2a)
+ pedwarn (loc, 0, "pack init-capture only available with "
+ "%<-std=c++2a%> or %<-std=gnu++2a%>");
+ cp_lexer_consume_token (parser->lexer);
+ init_pack_expansion = true;
+ }
+
/* Remember whether we want to capture as a reference or not. */
if (cp_lexer_next_token_is (parser->lexer, CPP_AND))
{
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;
error ("empty initializer for lambda init-capture");
capture_init_expr = error_mark_node;
}
+ if (init_pack_expansion)
+ capture_init_expr = make_pack_expansion (capture_init_expr);
}
else
{
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);
begin_scope (sk_function_parms, /*entity=*/NULL_TREE);
/* Parse parameters. */
- param_list = cp_parser_parameter_declaration_clause (parser);
+ param_list
+ = cp_parser_parameter_declaration_clause
+ (parser, CP_PARSER_FLAGS_TYPENAME_OPTIONAL);
/* Default arguments shall not be specified in the
parameter-declaration-clause of a lambda-declarator. */
parens.require_close (parser);
- attributes = cp_parser_attributes_opt (parser);
-
/* In the decl-specifier-seq of the lambda-declarator, each
decl-specifier shall either be mutable or constexpr. */
int declares_class_or_enum;
/* Parse optional exception specification. */
exception_spec = cp_parser_exception_specification_opt (parser);
+ attributes = cp_parser_std_attribute_spec_seq (parser);
+
/* Parse optional trailing return type. */
if (cp_lexer_next_token_is (parser->lexer, CPP_DEREF))
{
= 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);
- declarator = make_id_declarator (NULL_TREE, call_op_identifier, sfk_none);
+ declarator = make_id_declarator (NULL_TREE, call_op_identifier, sfk_none,
+ LAMBDA_EXPR_LOCATION (lambda_expr));
quals = (LAMBDA_EXPR_MUTABLE_P (lambda_expr)
? TYPE_UNQUALIFIED : TYPE_QUAL_CONST);
REF_QUAL_NONE,
tx_qual,
exception_spec,
- /*late_return_type=*/NULL_TREE,
+ return_type,
/*requires_clause*/NULL_TREE);
- declarator->id_loc = LAMBDA_EXPR_LOCATION (lambda_expr);
- if (return_type)
- declarator->u.function.late_return_type = return_type;
+ declarator->std_attributes = attributes;
fco = grokmethod (&return_type_specs,
declarator,
- attributes);
+ NULL_TREE);
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)) = get_identifier ("__closure");
+ DECL_NAME (DECL_ARGUMENTS (fco)) = closure_identifier;
+ DECL_LAMBDA_FUNCTION (fco) = 1;
}
if (template_param_list)
{
cp_parser_lambda_body (cp_parser* parser, tree lambda_expr)
{
bool nested = (current_function_decl != NULL_TREE);
- bool local_variables_forbidden_p = parser->local_variables_forbidden_p;
+ unsigned char local_variables_forbidden_p
+ = parser->local_variables_forbidden_p;
bool in_function_body = parser->in_function_body;
+ /* The body of a lambda-expression is not a subexpression of the enclosing
+ expression. */
+ cp_evaluated ev;
+
if (nested)
push_function_context ();
else
vec<tree> omp_privatization_save;
save_omp_privatization_clauses (omp_privatization_save);
/* Clear this in case we're in the middle of a default argument. */
- parser->local_variables_forbidden_p = false;
+ parser->local_variables_forbidden_p = 0;
parser->in_function_body = true;
{
{
tree statement, std_attrs = NULL_TREE;
cp_token *token;
- location_t statement_location, attrs_location;
+ location_t statement_location, attrs_loc;
restart:
if (if_p != NULL)
statement = NULL_TREE;
saved_token_sentinel saved_tokens (parser->lexer);
- attrs_location = cp_lexer_peek_token (parser->lexer)->location;
+ attrs_loc = cp_lexer_peek_token (parser->lexer)->location;
if (c_dialect_objc ())
/* In obj-c++, seeing '[[' might be the either the beginning of
c++11 attributes, or a nested objc-message-expression. So
let's parse the c++11 attributes tentatively. */
cp_parser_parse_tentatively (parser);
std_attrs = cp_parser_std_attribute_spec_seq (parser);
+ if (std_attrs)
+ {
+ location_t end_loc
+ = cp_lexer_previous_token (parser->lexer)->location;
+ attrs_loc = make_location (attrs_loc, attrs_loc, end_loc);
+ }
if (c_dialect_objc ())
{
if (!cp_parser_parse_definitely (parser))
/* Peek at the next token. */
token = cp_lexer_peek_token (parser->lexer);
/* Remember the location of the first token in the statement. */
+ cp_token *statement_token = token;
statement_location = token->location;
add_debug_begin_stmt (statement_location);
/* If this is a keyword, then that will often determine what kind of
case RID_IF:
case RID_SWITCH:
+ std_attrs = process_stmt_hotness_attribute (std_attrs, attrs_loc);
statement = cp_parser_selection_statement (parser, if_p, chain);
break;
case RID_WHILE:
case RID_DO:
case RID_FOR:
+ std_attrs = process_stmt_hotness_attribute (std_attrs, attrs_loc);
statement = cp_parser_iteration_statement (parser, if_p, false, 0);
break;
case RID_CONTINUE:
case RID_RETURN:
case RID_GOTO:
+ std_attrs = process_stmt_hotness_attribute (std_attrs, attrs_loc);
statement = cp_parser_jump_statement (parser);
break;
case RID_AT_FINALLY:
case RID_AT_SYNCHRONIZED:
case RID_AT_THROW:
+ std_attrs = process_stmt_hotness_attribute (std_attrs, attrs_loc);
statement = cp_parser_objc_statement (parser);
break;
case RID_TRY:
+ std_attrs = process_stmt_hotness_attribute (std_attrs, attrs_loc);
statement = cp_parser_try_block (parser);
break;
case RID_NAMESPACE:
/* This must be a namespace alias definition. */
+ if (std_attrs != NULL_TREE)
+ {
+ /* Attributes should be parsed as part of the the
+ declaration, so let's un-parse them. */
+ saved_tokens.rollback();
+ std_attrs = NULL_TREE;
+ }
cp_parser_declaration_statement (parser);
return;
case RID_SYNCHRONIZED:
case RID_ATOMIC_NOEXCEPT:
case RID_ATOMIC_CANCEL:
+ std_attrs = process_stmt_hotness_attribute (std_attrs, attrs_loc);
statement = cp_parser_transaction (parser, token);
break;
case RID_TRANSACTION_CANCEL:
+ std_attrs = process_stmt_hotness_attribute (std_attrs, attrs_loc);
statement = cp_parser_transaction_cancel (parser);
break;
if (cp_lexer_next_token_is_not (parser->lexer, CPP_SEMICOLON))
{
if (std_attrs != NULL_TREE)
- {
- /* Attributes should be parsed as part of the the
- declaration, so let's un-parse them. */
- saved_tokens.rollback();
- std_attrs = NULL_TREE;
- }
+ /* Attributes should be parsed as part of the declaration,
+ so let's un-parse them. */
+ saved_tokens.rollback();
cp_parser_parse_tentatively (parser);
/* Try to parse the declaration-statement. */
/* If that worked, we're done. */
if (cp_parser_parse_definitely (parser))
return;
+ /* It didn't work, restore the post-attribute position. */
+ if (std_attrs)
+ cp_lexer_set_token_position (parser->lexer, statement_token);
}
/* All preceding labels have been parsed at this point. */
if (loc_after_labels != NULL)
*loc_after_labels = statement_location;
+ std_attrs = process_stmt_hotness_attribute (std_attrs, attrs_loc);
+
/* Look for an expression-statement instead. */
statement = cp_parser_expression_statement (parser, in_statement_expr);
/* Allow "[[fallthrough]];", but warn otherwise. */
if (std_attrs != NULL_TREE)
- warning_at (attrs_location,
+ warning_at (attrs_loc,
OPT_Wattributes,
"attributes at the beginning of statement are ignored");
}
{
tree l = finish_case_label (token->location, expr, expr_hi);
if (l && TREE_CODE (l) == CASE_LABEL_EXPR)
- FALLTHROUGH_LABEL_P (CASE_LABEL (l)) = fallthrough_p;
+ {
+ label = CASE_LABEL (l);
+ FALLTHROUGH_LABEL_P (label) = fallthrough_p;
+ }
}
else
error_at (token->location,
{
tree l = finish_case_label (token->location, NULL_TREE, NULL_TREE);
if (l && TREE_CODE (l) == CASE_LABEL_EXPR)
- FALLTHROUGH_LABEL_P (CASE_LABEL (l)) = fallthrough_p;
+ {
+ label = CASE_LABEL (l);
+ FALLTHROUGH_LABEL_P (label) = fallthrough_p;
+ }
}
else
error_at (token->location, "case label not within a switch statement");
cp_parser_parse_tentatively (parser);
attrs = cp_parser_gnu_attributes_opt (parser);
if (attrs == NULL_TREE
+ /* And fallthrough always binds to the expression-statement. */
+ || attribute_fallthrough_p (attrs)
|| cp_lexer_next_token_is_not (parser->lexer, CPP_SEMICOLON))
cp_parser_abort_tentative_parse (parser);
else if (!cp_parser_parse_definitely (parser))
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);
}
/* Parse the declarator. */
declarator = cp_parser_declarator (parser, CP_PARSER_DECLARATOR_NAMED,
+ CP_PARSER_FLAGS_NONE,
/*ctor_dtor_or_conv_p=*/NULL,
/*parenthesized_p=*/NULL,
/*member_p=*/false,
- /*friend_p=*/false);
+ /*friend_p=*/false,
+ /*static_p=*/false);
/* Parse the attributes. */
attributes = cp_parser_attributes_opt (parser);
/* Parse the asm-specification. */
if (cp_parser_parse_definitely (parser))
{
tree pushed_scope;
- bool non_constant_p;
+ bool non_constant_p = false;
int flags = LOOKUP_ONLYCONVERTING;
if (!cp_parser_check_condition_declarator (parser, declarator, loc))
is_range_for = cp_parser_init_statement (parser, &decl);
if (is_range_for)
- return cp_parser_range_for (parser, scope, init, decl, ivdep, unroll);
+ return cp_parser_range_for (parser, scope, init, decl, ivdep, unroll,
+ false);
else
return cp_parser_c_for (parser, scope, init, ivdep, unroll);
}
static tree
cp_parser_range_for (cp_parser *parser, tree scope, tree init, tree range_decl,
- bool ivdep, unsigned short unroll)
+ bool ivdep, unsigned short unroll, bool is_omp)
{
tree stmt, range_expr;
auto_vec <cxx_binding *, 16> bindings;
IDENTIFIER_BINDING (names[i]) = binding;
}
+ /* finish_omp_for has its own code for the following, so just
+ return the range_expr instead. */
+ if (is_omp)
+ return range_expr;
+
/* If in template, STMT is converted to a normal for-statement
at instantiation. If not, it is done just ahead. */
if (processing_template_decl)
type_uses_auto (range_type));
/* Create the __range variable. */
- range_temp = build_decl (input_location, VAR_DECL,
- get_identifier ("__for_range"), range_type);
+ range_temp = build_decl (input_location, VAR_DECL, for_range__identifier,
+ range_type);
TREE_USED (range_temp) = 1;
DECL_ARTIFICIAL (range_temp) = 1;
}
/* The new for initialization statement. */
- begin = build_decl (input_location, VAR_DECL,
- get_identifier ("__for_begin"), iter_type);
+ begin = build_decl (input_location, VAR_DECL, for_begin__identifier,
+ iter_type);
TREE_USED (begin) = 1;
DECL_ARTIFICIAL (begin) = 1;
pushdecl (begin);
if (cxx_dialect >= cxx17)
iter_type = cv_unqualified (TREE_TYPE (end_expr));
- end = build_decl (input_location, VAR_DECL,
- get_identifier ("__for_end"), iter_type);
+ end = build_decl (input_location, VAR_DECL, for_end__identifier, iter_type);
TREE_USED (end) = 1;
DECL_ARTIFICIAL (end) = 1;
pushdecl (end);
{
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;
}
}
cp_lexer_consume_token (parser->lexer);
is_range_for = true;
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");
- *decl = error_mark_node;
- }
+ pedwarn (cp_lexer_peek_token (parser->lexer)->location, 0,
+ "range-based %<for%> loops only available with "
+ "%<-std=c++11%> or %<-std=gnu++11%>");
}
else
/* The ';' is not consumed yet because we told
{
while (true)
{
- cp_token *token;
-
- token = cp_lexer_peek_token (parser->lexer);
+ cp_token *token = cp_lexer_peek_token (parser->lexer);
if (token->type == CPP_CLOSE_BRACE
- || token->type == CPP_EOF
- || token->type == CPP_PRAGMA_EOL)
+ || token->type == CPP_EOF)
break;
-
- if (token->type == CPP_SEMICOLON)
- {
- /* A declaration consisting of a single semicolon is
- invalid. Allow it unless we're being pedantic. */
- cp_lexer_consume_token (parser->lexer);
- if (!in_system_header_at (input_location))
- pedwarn (input_location, OPT_Wpedantic, "extra %<;%>");
- continue;
- }
-
- /* If we're entering or exiting a region that's implicitly
- extern "C", modify the lang context appropriately. */
- if (!parser->implicit_extern_c && token->implicit_extern_c)
- {
- push_lang_context (lang_name_c);
- parser->implicit_extern_c = true;
- }
- else if (parser->implicit_extern_c && !token->implicit_extern_c)
- {
- pop_lang_context ();
- parser->implicit_extern_c = false;
- }
-
- if (token->type == CPP_PRAGMA)
- {
- /* A top-level declaration can consist solely of a #pragma.
- A nested declaration cannot, so this is done here and not
- in cp_parser_declaration. (A #pragma at block scope is
- handled in cp_parser_statement.) */
- cp_parser_pragma (parser, pragma_external, NULL);
- continue;
- }
-
- /* Parse the declaration itself. */
- cp_parser_declaration (parser);
+ else
+ cp_parser_toplevel_declaration (parser);
}
}
obstack_free (&declarator_obstack, p);
}
+/* Parse a namespace-scope declaration. */
+
+static void
+cp_parser_toplevel_declaration (cp_parser* parser)
+{
+ cp_token *token = cp_lexer_peek_token (parser->lexer);
+
+ if (token->type == CPP_PRAGMA)
+ /* A top-level declaration can consist solely of a #pragma. A
+ nested declaration cannot, so this is done here and not in
+ cp_parser_declaration. (A #pragma at block scope is
+ handled in cp_parser_statement.) */
+ cp_parser_pragma (parser, pragma_external, NULL);
+ else if (token->type == CPP_SEMICOLON)
+ {
+ /* A declaration consisting of a single semicolon is
+ invalid. Allow it unless we're being pedantic. */
+ cp_lexer_consume_token (parser->lexer);
+ if (!in_system_header_at (input_location))
+ pedwarn (input_location, OPT_Wpedantic, "extra %<;%>");
+ }
+ else
+ /* Parse the declaration itself. */
+ cp_parser_declaration (parser);
+}
+
/* Parse a block-declaration.
block-declaration:
saw_declarator = true;
/* Parse the init-declarator. */
- decl = cp_parser_init_declarator (parser, &decl_specifiers,
+ decl = cp_parser_init_declarator (parser,
+ CP_PARSER_FLAGS_NONE,
+ &decl_specifiers,
/*checks=*/NULL,
function_definition_allowed_p,
/*member_p=*/false,
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);
FOR_EACH_VEC_ELT (v, i, e)
{
if (i == 0)
- declarator = make_id_declarator (NULL_TREE, e.get_value (), sfk_none);
+ declarator = make_id_declarator (NULL_TREE, e.get_value (),
+ sfk_none, e.get_location ());
else
- declarator->u.id.unqualified_name = e.get_value ();
- declarator->id_loc = e.get_location ();
+ {
+ declarator->u.id.unqualified_name = e.get_value ();
+ declarator->id_loc = e.get_location ();
+ }
tree elt_pushed_scope;
tree decl2 = start_decl (declarator, &decl_specs, SD_INITIALIZED,
NULL_TREE, NULL_TREE, &elt_pushed_scope);
found_decl_spec = true;
if (!is_cv_qualifier)
decl_specs->any_type_specifiers_p = true;
+
+ if ((flags & CP_PARSER_FLAGS_ONLY_MUTABLE_OR_CONSTEXPR) != 0)
+ error_at (token->location, "type-specifier invalid in lambda");
}
}
virtual
explicit
+ C++2A Extension:
+ explicit(constant-expression)
+
Returns an IDENTIFIER_NODE corresponding to the keyword used.
Updates DECL_SPECS, if it is non-NULL. */
break;
case RID_EXPLICIT:
- set_and_check_decl_spec_loc (decl_specs, ds_explicit, token);
- break;
+ {
+ tree id = cp_lexer_consume_token (parser->lexer)->u.value;
+ /* If we see '(', it's C++20 explicit(bool). */
+ tree expr;
+ if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_PAREN))
+ {
+ matching_parens parens;
+ parens.consume_open (parser);
+
+ /* New types are not allowed in an explicit-specifier. */
+ const char *saved_message
+ = parser->type_definition_forbidden_message;
+ parser->type_definition_forbidden_message
+ = G_("types may not be defined in explicit-specifier");
+
+ if (cxx_dialect < cxx2a)
+ pedwarn (token->location, 0,
+ "%<explicit(bool)%> only available with %<-std=c++2a%> "
+ "or %<-std=gnu++2a%>");
+
+ /* Parse the constant-expression. */
+ expr = cp_parser_constant_expression (parser);
+
+ /* Restore the saved message. */
+ parser->type_definition_forbidden_message = saved_message;
+ parens.require_close (parser);
+ }
+ else
+ /* The explicit-specifier explicit without a constant-expression is
+ equivalent to the explicit-specifier explicit(true). */
+ expr = boolean_true_node;
+
+ /* [dcl.fct.spec]
+ "the constant-expression, if supplied, shall be a contextually
+ converted constant expression of type bool." */
+ expr = build_explicit_specifier (expr, tf_warning_or_error);
+ /* We could evaluate it -- mark the decl as appropriate. */
+ if (expr == boolean_true_node)
+ set_and_check_decl_spec_loc (decl_specs, ds_explicit, token);
+ else if (expr == boolean_false_node)
+ /* Don't mark the decl as explicit. */;
+ else if (decl_specs)
+ /* The expression was value-dependent. Remember it so that we can
+ substitute it later. */
+ decl_specs->explicit_specifier = expr;
+ return id;
+ }
default:
return NULL_TREE;
/* Consume the `{' token. */
matching_braces braces;
- braces.consume_open (parser)->location;
+ braces.consume_open (parser);
/* Parse the declarations. */
cp_parser_declaration_seq_opt (parser);
/* Look for the closing `}'. */
if (cxx_dialect < cxx17)
pedwarn (input_location, OPT_Wpedantic,
"static_assert without a message "
- "only available with -std=c++17 or -std=gnu++17");
+ "only available with %<-std=c++17%> or %<-std=gnu++17%>");
/* Eat the ')' */
cp_lexer_consume_token (parser->lexer);
message = build_string (1, "");
++c_inhibit_evaluation_warnings;
expr = cp_parser_decltype_expr (parser, id_expression_or_member_access_p);
+ STRIP_ANY_LOCATION_WRAPPER (expr);
/* Go back to evaluating expressions. */
--cp_unevaluated_operand;
= G_("types may not be defined in a conversion-type-id");
/* Parse the type-specifiers. */
- cp_parser_type_specifier_seq (parser, /*is_declaration=*/false,
+ cp_parser_type_specifier_seq (parser, CP_PARSER_FLAGS_NONE,
+ /*is_declaration=*/false,
/*is_trailing_return=*/false,
&type_specifiers);
vec = cp_parser_parenthesized_expression_list (parser, non_attr,
/*cast_p=*/false,
/*allow_expansion_p=*/true,
- /*non_constant_p=*/NULL);
+ /*non_constant_p=*/NULL,
+ /*close_paren_loc=*/NULL,
+ /*wrap_locations_p=*/true);
if (vec == NULL)
return error_mark_node;
expression_list = build_tree_list_vec (vec);
static cp_expr
cp_parser_operator_function_id (cp_parser* parser)
{
+ location_t start_loc = cp_lexer_peek_token (parser->lexer)->location;
/* Look for the `operator' keyword. */
if (!cp_parser_require_keyword (parser, RID_OPERATOR, RT_OPERATOR))
return error_mark_node;
/* And then the name of the operator itself. */
- return cp_parser_operator (parser);
+ return cp_parser_operator (parser, start_loc);
}
/* Return an identifier node for a user-defined literal operator.
human-readable spelling of the identifier, e.g., `operator +'. */
static cp_expr
-cp_parser_operator (cp_parser* parser)
+cp_parser_operator (cp_parser* parser, location_t start_loc)
{
tree id = NULL_TREE;
cp_token *token;
/* Peek at the next token. */
token = cp_lexer_peek_token (parser->lexer);
- location_t start_loc = token->location;
+ location_t end_loc = token->location;
/* Figure out which operator we have. */
enum tree_code op = ERROR_MARK;
break;
/* Consume the `new' or `delete' token. */
- location_t end_loc = cp_lexer_consume_token (parser->lexer)->location;
+ end_loc = cp_lexer_consume_token (parser->lexer)->location;
/* Peek at the next token. */
token = cp_lexer_peek_token (parser->lexer);
end_loc = close_token->location;
op = op == NEW_EXPR ? VEC_NEW_EXPR : VEC_DELETE_EXPR;
}
- start_loc = make_location (start_loc, start_loc, end_loc);
consumed = true;
break;
}
matching_parens parens;
parens.consume_open (parser);
/* Look for the matching `)'. */
- parens.require_close (parser);
+ token = parens.require_close (parser);
+ if (token)
+ end_loc = token->location;
op = CALL_EXPR;
consumed = true;
break;
/* Consume the `['. */
cp_lexer_consume_token (parser->lexer);
/* Look for the matching `]'. */
- cp_parser_require (parser, CPP_CLOSE_SQUARE, RT_CLOSE_SQUARE);
+ token = cp_parser_require (parser, CPP_CLOSE_SQUARE, RT_CLOSE_SQUARE);
+ if (token)
+ end_loc = token->location;
op = ARRAY_REF;
consumed = true;
break;
case CPP_STRING16_USERDEF:
case CPP_STRING32_USERDEF:
{
- tree str, string_tree;
+ cp_expr str;
+ tree string_tree;
int sz, len;
if (cxx_dialect == cxx98)
return error_mark_node;
else if (TREE_CODE (str) == USERDEF_LITERAL)
{
- string_tree = USERDEF_LITERAL_VALUE (str);
- id = USERDEF_LITERAL_SUFFIX_ID (str);
+ string_tree = USERDEF_LITERAL_VALUE (str.get_value ());
+ id = USERDEF_LITERAL_SUFFIX_ID (str.get_value ());
+ end_loc = str.get_location ();
}
else
{
/* Look for the suffix identifier. */
token = cp_lexer_peek_token (parser->lexer);
if (token->type == CPP_NAME)
- id = cp_parser_identifier (parser);
+ {
+ id = cp_parser_identifier (parser);
+ end_loc = token->location;
+ }
else if (token->type == CPP_KEYWORD)
{
error ("unexpected keyword;"
const char *name = IDENTIFIER_POINTER (id);
id = cp_literal_operator_id (name);
}
- return id;
+ /* Generate a location of the form:
+ "" _suffix_identifier
+ ^~~~~~~~~~~~~~~~~~~~~
+ 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);
+ return cp_expr (id, combined_loc);
}
default:
id = error_mark_node;
}
+ start_loc = make_location (start_loc, start_loc, get_finish (end_loc));
return cp_expr (id, start_loc);
}
{
tree parameter_list = NULL_TREE;
+ /* Don't create wrapper nodes within a template-parameter-list,
+ since we don't want to have different types based on the
+ spelling location of constants and decls within them. */
+ auto_suppress_location_wrappers sentinel;
+
begin_template_parm_list ();
/* The loop below parses the template parms. We first need to know
if (is_pack)
cp_lexer_consume_token (parser->lexer);
+ tree identifier = cp_parser_identifier (parser);
+ if (identifier == error_mark_node)
+ break;
+
/* Build placeholder. */
tree parm = build_nt (WILDCARD_DECL);
DECL_SOURCE_LOCATION (parm)
= cp_lexer_peek_token (parser->lexer)->location;
- DECL_NAME (parm) = cp_parser_identifier (parser);
+ DECL_NAME (parm) = identifier;
WILDCARD_PACK_P (parm) = is_pack;
vec_safe_push (introduction_vec, parm);
/* Parse the default-argument. */
push_deferring_access_checks (dk_no_deferred);
- tree default_argument = cp_parser_type_id (parser);
+ tree default_argument = cp_parser_type_id (parser,
+ CP_PARSER_FLAGS_TYPENAME_OPTIONAL,
+ NULL);
pop_deferring_access_checks ();
if (flag_concepts && type_uses_auto (default_argument))
of the template parameter-list rather than a greater-than
operator. */
parameter_declarator
- = cp_parser_parameter_declaration (parser, /*template_parm_p=*/true,
+ = cp_parser_parameter_declaration (parser,
+ CP_PARSER_FLAGS_TYPENAME_OPTIONAL,
+ /*template_parm_p=*/true,
/*parenthesized_p=*/NULL);
if (!parameter_declarator)
is_declaration,
tag_type,
&is_identifier);
+
+ /* Push any access checks inside the firewall we're about to create. */
+ vec<deferred_access_check, va_gc> *checks = get_deferred_access_checks ();
+ pop_deferring_access_checks ();
if (templ == error_mark_node || is_identifier)
- {
- pop_deferring_access_checks ();
- return templ;
- }
+ return templ;
/* Since we're going to preserve any side-effects from this parse, set up a
firewall to protect our callers from cp_parser_commit_to_tentative_parse
in the template arguments. */
tentative_firewall firewall (parser);
+ reopen_deferring_access_checks (checks);
/* If we find the sequence `[:' after a template-name, it's probably
a digraph-typo for `< ::'. Substitute the tokens and check if we can
}
/* Parse the arguments. */
arguments = cp_parser_enclosed_template_argument_list (parser);
+
+ if ((cxx_dialect > cxx17)
+ && (TREE_CODE (templ) == FUNCTION_DECL || identifier_p (templ))
+ && !template_keyword_p
+ && (cp_parser_error_occurred (parser)
+ || cp_lexer_next_token_is_not (parser->lexer, CPP_OPEN_PAREN)))
+ {
+ /* This didn't go well. */
+ if (TREE_CODE (templ) == FUNCTION_DECL)
+ {
+ /* C++2A says that "function-name < a;" is now ill-formed. */
+ if (cp_parser_error_occurred (parser))
+ {
+ error_at (token->location, "invalid template-argument-list");
+ inform (token->location, "function name as the left hand "
+ "operand of %<<%> is ill-formed in C++2a; wrap the "
+ "function name in %<()%>");
+ }
+ else
+ /* We expect "f<targs>" to be followed by "(args)". */
+ error_at (cp_lexer_peek_token (parser->lexer)->location,
+ "expected %<(%> after template-argument-list");
+ if (start_of_id)
+ /* Purge all subsequent tokens. */
+ cp_lexer_purge_tokens_after (parser->lexer, start_of_id);
+ }
+ else
+ cp_parser_simulate_error (parser);
+ pop_deferring_access_checks ();
+ return error_mark_node;
+ }
}
/* Set the location to be of the form:
else if (DECL_TYPE_TEMPLATE_P (templ)
|| DECL_TEMPLATE_TEMPLATE_PARM_P (templ))
{
- bool entering_scope;
/* In "template <typename T> ... A<T>::", A<T> is the abstract A
template (rather than some instantiation thereof) only if
is not nested within some other construct. For example, in
"template <typename T> void f(T) { A<T>::", A<T> is just an
instantiation of A. */
- entering_scope = (template_parm_scope_p ()
- && cp_lexer_next_token_is (parser->lexer,
- CPP_SCOPE));
+ bool entering_scope
+ = (template_parm_scope_p ()
+ && cp_lexer_next_token_is (parser->lexer, CPP_SCOPE));
template_id
= finish_template_type (templ, arguments, entering_scope);
}
a function-template. */
gcc_assert ((DECL_FUNCTION_TEMPLATE_P (templ)
|| TREE_CODE (templ) == OVERLOAD
+ || TREE_CODE (templ) == FUNCTION_DECL
|| BASELINK_P (templ)));
template_id = lookup_template_function (templ, arguments);
token->type = CPP_TEMPLATE_ID;
token->location = combined_loc;
- /* We must mark the lookup as kept, so we don't throw it away on
- the first parse. */
- if (is_overloaded_fn (template_id))
- lookup_keep (get_fns (template_id), true);
-
/* Retrieve any deferred checks. Do not pop this access checks yet
so the memory will not be reclaimed during token replacing below. */
token->u.tree_check_value = ggc_cleared_alloc<struct tree_check> ();
}
}
+ /* cp_parser_lookup_name clears OBJECT_TYPE. */
+ const bool scoped_p = ((parser->scope ? parser->scope
+ : parser->context->object_type) != NULL_TREE);
+
/* Look up the name. */
decl = cp_parser_lookup_name (parser, identifier,
tag_type,
if (TREE_CODE (*iter) == TEMPLATE_DECL)
found = true;
+ if (!found
+ && (cxx_dialect > cxx17)
+ && !scoped_p
+ && cp_lexer_next_token_is (parser->lexer, CPP_LESS)
+ && tag_type == none_type)
+ {
+ /* [temp.names] says "A name is also considered to refer to a template
+ if it is an unqualified-id followed by a < and name lookup finds
+ either one or more functions or finds nothing." */
+
+ /* The "more functions" case. Just use the OVERLOAD as normally.
+ We don't use is_overloaded_fn here to avoid considering
+ BASELINKs. */
+ if (TREE_CODE (decl) == OVERLOAD
+ /* Name lookup found one function. */
+ || TREE_CODE (decl) == FUNCTION_DECL)
+ found = true;
+ /* Name lookup found nothing. */
+ else if (decl == error_mark_node)
+ return identifier;
+ }
+
if (!found)
{
/* The name does not name a template. */
}
}
- /* If DECL is dependent, and refers to a function, then just return
- its name; we will look it up again during template instantiation. */
- if (DECL_FUNCTION_TEMPLATE_P (decl) || !DECL_P (decl))
- {
- tree scope = ovl_scope (decl);
- if (TYPE_P (scope) && dependent_type_p (scope))
- return identifier;
- }
-
return decl;
}
bool saved_ice_p;
bool saved_non_ice_p;
+ /* Don't create location wrapper nodes within a template-argument-list. */
+ auto_suppress_location_wrappers sentinel;
+
saved_in_template_argument_list_p = parser->in_template_argument_list_p;
parser->in_template_argument_list_p = true;
/* Even if the template-id appears in an integral
argument = cp_parser_constant_expression (parser);
else
{
+ /* In C++20, we can encounter a braced-init-list. */
+ if (cxx_dialect >= cxx2a
+ && cp_lexer_next_token_is (parser->lexer, CPP_OPEN_BRACE))
+ {
+ bool expr_non_constant_p;
+ return cp_parser_braced_list (parser, &expr_non_constant_p);
+ }
+
/* With C++17 generalized non-type template arguments we need to handle
lvalue constant expressions, too. */
argument = cp_parser_assignment_expression (parser);
/* Parse the declarator. */
declarator
= cp_parser_declarator (parser, CP_PARSER_DECLARATOR_NAMED,
+ CP_PARSER_FLAGS_NONE,
/*ctor_dtor_or_conv_p=*/NULL,
/*parenthesized_p=*/NULL,
/*member_p=*/false,
- /*friend_p=*/false);
+ /*friend_p=*/false,
+ /*static_p=*/false);
if (declares_class_or_enum & 2)
cp_parser_check_for_definition_in_return_type (declarator,
decl_specifiers.type,
decl_specs->explicit_char_p = true;
type = char_type_node;
break;
+ case RID_CHAR8:
+ type = char8_type_node;
+ break;
case RID_CHAR16:
type = char16_type_node;
break;
error_at (token->location,
"use of %<auto%> in lambda parameter declaration "
"only available with "
- "-std=c++14 or -std=gnu++14");
+ "%<-std=c++14%> or %<-std=gnu++14%>");
}
else if (cxx_dialect < cxx14)
error_at (token->location,
"use of %<auto%> in parameter declaration "
"only available with "
- "-std=c++14 or -std=gnu++14");
+ "%<-std=c++14%> or %<-std=gnu++14%>");
else if (!flag_concepts)
pedwarn (token->location, 0,
"use of %<auto%> in parameter declaration "
- "only available with -fconcepts");
+ "only available with %<-fconcepts%>");
}
else
type = make_auto ();
{
bool qualified_p;
bool global_p;
+ const bool typename_p = (cxx_dialect >= cxx2a
+ && (flags & CP_PARSER_FLAGS_TYPENAME_OPTIONAL));
/* Don't gobble tokens or issue error messages if this is an
optional type-specifier. */
luck. */
if (TREE_CODE (type) != TYPE_DECL)
{
- cp_parser_error (parser, "expected template-id for type");
- type = NULL_TREE;
+ /* ...unless we pretend we have seen 'typename'. */
+ if (typename_p)
+ type = cp_parser_make_typename_type (parser, type,
+ token->location);
+ else
+ {
+ cp_parser_error (parser, "expected template-id for type");
+ type = NULL_TREE;
+ }
}
}
/* Otherwise, look for a type-name. */
else
- type = cp_parser_type_name (parser);
+ type = cp_parser_type_name (parser, (qualified_p && typename_p));
+
/* Keep track of all name-lookups performed in class scopes. */
if (type
&& !global_p
Returns a TYPE_DECL for the type. */
-static tree
-cp_parser_type_name (cp_parser* parser)
-{
- return cp_parser_type_name (parser, /*typename_keyword_p=*/false);
-}
-
-/* See above. */
static tree
cp_parser_type_name (cp_parser* parser, bool typename_keyword_p)
{
|| cp_parser_is_keyword (token, RID_STRUCT))
{
gcc_rich_location richloc (token->location);
- richloc.add_range (input_location, false);
+ richloc.add_range (input_location);
richloc.add_fixit_remove ();
pedwarn (&richloc, 0, "elaborated-type-specifier for "
"a scoped enum must not use the %qD keyword",
template-id or not. */
if (!template_p)
cp_parser_parse_tentatively (parser);
+ /* The `template' keyword must follow a nested-name-specifier. */
+ else if (!nested_name_specifier)
+ {
+ cp_parser_error (parser, "%<template%> must follow a nested-"
+ "name-specifier");
+ return error_mark_node;
+ }
+
/* Parse the template-id. */
token = cp_lexer_peek_token (parser->lexer);
decl = cp_parser_template_id (parser, template_p,
cp_lexer_consume_token (parser->lexer);
/* Parse the type-specifier-seq. */
- cp_parser_type_specifier_seq (parser, /*is_declaration=*/false,
+ cp_parser_type_specifier_seq (parser, CP_PARSER_FLAGS_NONE,
+ /*is_declaration=*/false,
/*is_trailing_return=*/false,
&type_specifiers);
{
if (!cp_parser_uncommitted_to_tentative_parse_p (parser))
{
- error_at (token->location, "%qD is not a namespace-name", identifier);
+ auto_diagnostic_group d;
+ name_hint hint;
if (namespace_decl == error_mark_node
&& parser->scope && TREE_CODE (parser->scope) == NAMESPACE_DECL)
- suggest_alternative_in_explicit_scope (token->location, identifier,
- parser->scope);
+ hint = suggest_alternative_in_explicit_scope (token->location,
+ identifier,
+ parser->scope);
+ if (const char *suggestion = hint.suggestion ())
+ {
+ gcc_rich_location richloc (token->location);
+ richloc.add_fixit_replace (suggestion);
+ error_at (&richloc,
+ "%qD is not a namespace-name; did you mean %qs?",
+ identifier, suggestion);
+ }
+ else
+ error_at (token->location, "%qD is not a namespace-name",
+ identifier);
}
- cp_parser_error (parser, "expected namespace-name");
+ else
+ cp_parser_error (parser, "expected namespace-name");
namespace_decl = error_mark_node;
}
cp_ensure_no_oacc_routine (parser);
bool is_inline = cp_lexer_next_token_is_keyword (parser->lexer, RID_INLINE);
+ const bool topmost_inline_p = is_inline;
if (is_inline)
{
{
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%>");
+ cp_lexer_consume_token (parser->lexer);
+ }
+
if (cp_lexer_next_token_is (parser->lexer, CPP_NAME))
{
identifier = cp_parser_identifier (parser);
}
if (cp_lexer_next_token_is_not (parser->lexer, CPP_SCOPE))
- break;
+ {
+ /* Don't forget that the innermost namespace might have been
+ marked as inline. Use |= because we cannot overwrite
+ IS_INLINE in case the outermost namespace is inline, but
+ there are no nested inlines. */
+ 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 (int count = identifier ? push_namespace (identifier) : 0)
+ if (int count = (identifier
+ ? push_namespace (identifier, nested_inline_p)
+ : 0))
nested_definition_count += count;
else
cp_parser_error (parser, "nested namespace name required");
if (nested_definition_count && attribs)
error_at (token->location,
"a nested namespace definition cannot have attributes");
- if (nested_definition_count && is_inline)
+ if (nested_definition_count && topmost_inline_p)
error_at (token->location,
"a nested namespace definition cannot be inline");
bool has_visibility = handle_namespace_attrs (current_namespace, attribs);
- warning (OPT_Wnamespaces, "namespace %qD entered", current_namespace);
+ warning (OPT_Wnamespaces, "namespace %qD entered", current_namespace);
/* Look for the `{' to validate starting the namespace. */
matching_braces braces;
/*is_declaration=*/true);
if (!qscope)
qscope = global_namespace;
- else if (UNSCOPED_ENUM_P (qscope))
+ else if (UNSCOPED_ENUM_P (qscope)
+ && !TYPE_FUNCTION_SCOPE_P (qscope))
qscope = CP_TYPE_CONTEXT (qscope);
if (access_declaration_p && cp_parser_error_occurred (parser))
&& !in_system_header_at (ell->location))
pedwarn (ell->location, 0,
"pack expansion in using-declaration only available "
- "with -std=c++17 or -std=gnu++17");
+ "with %<-std=c++17%> or %<-std=gnu++17%>");
qscope = make_pack_expansion (qscope);
}
if (cxx_dialect < cxx17)
pedwarn (comma->location, 0,
"comma-separated list in using-declaration only available "
- "with -std=c++17 or -std=gnu++17");
+ "with %<-std=c++17%> or %<-std=gnu++17%>");
goto again;
}
cp_parser_alias_declaration (cp_parser* parser)
{
tree id, type, decl, pushed_scope = NULL_TREE, attributes;
- location_t id_location;
+ location_t id_location, type_location;
cp_declarator *declarator;
cp_decl_specifier_seq decl_specs;
bool member_p;
G_("types may not be defined in alias template declarations");
}
- type = cp_parser_type_id (parser);
+ type = cp_parser_type_id (parser, CP_PARSER_FLAGS_TYPENAME_OPTIONAL,
+ &type_location);
/* Restore the error message if need be. */
if (parser->num_template_parameter_lists)
set_and_check_decl_spec_loc (&decl_specs,
ds_alias,
using_token);
+ decl_specs.locations[ds_type_spec] = type_location;
if (parser->num_template_parameter_lists
&& !cp_parser_check_template_parameters (parser,
/*declarator=*/NULL))
return error_mark_node;
- declarator = make_id_declarator (NULL_TREE, id, sfk_none);
- declarator->id_loc = id_location;
+ declarator = make_id_declarator (NULL_TREE, id, sfk_none, id_location);
member_p = at_class_scope_p ();
if (member_p)
/* Parse an asm-definition.
+ asm-qualifier:
+ volatile
+ inline
+ goto
+
+ asm-qualifier-list:
+ asm-qualifier
+ asm-qualifier-list asm-qualifier
+
asm-definition:
asm ( string-literal ) ;
GNU Extension:
asm-definition:
- asm volatile [opt] ( string-literal ) ;
- asm volatile [opt] ( string-literal : asm-operand-list [opt] ) ;
- asm volatile [opt] ( string-literal : asm-operand-list [opt]
- : asm-operand-list [opt] ) ;
- asm volatile [opt] ( string-literal : asm-operand-list [opt]
- : asm-operand-list [opt]
+ asm asm-qualifier-list [opt] ( string-literal ) ;
+ asm asm-qualifier-list [opt] ( string-literal : asm-operand-list [opt] ) ;
+ asm asm-qualifier-list [opt] ( string-literal : asm-operand-list [opt]
+ : asm-operand-list [opt] ) ;
+ asm asm-qualifier-list [opt] ( string-literal : asm-operand-list [opt]
+ : asm-operand-list [opt]
: asm-clobber-list [opt] ) ;
- asm volatile [opt] goto ( string-literal : : asm-operand-list [opt]
- : asm-clobber-list [opt]
- : asm-goto-list ) ; */
+ asm asm-qualifier-list [opt] ( string-literal : : asm-operand-list [opt]
+ : asm-clobber-list [opt]
+ : asm-goto-list ) ;
+
+ The form with asm-goto-list is valid if and only if the asm-qualifier-list
+ contains goto, and is the only allowed form in that case. No duplicates are
+ allowed in an asm-qualifier-list. */
static void
cp_parser_asm_definition (cp_parser* parser)
tree clobbers = NULL_TREE;
tree labels = NULL_TREE;
tree asm_stmt;
- bool volatile_p = false;
bool extended_p = false;
bool invalid_inputs_p = false;
bool invalid_outputs_p = false;
- bool goto_p = false;
required_token missing = RT_NONE;
/* Look for the `asm' keyword. */
cp_function_chain->invalid_constexpr = true;
}
- /* See if the next token is `volatile'. */
- if (cp_parser_allow_gnu_extensions_p (parser)
- && cp_lexer_next_token_is_keyword (parser->lexer, RID_VOLATILE))
- {
- /* Remember that we saw the `volatile' keyword. */
- volatile_p = true;
- /* Consume the token. */
- cp_lexer_consume_token (parser->lexer);
- }
- if (cp_parser_allow_gnu_extensions_p (parser)
- && parser->in_function_body
- && cp_lexer_next_token_is_keyword (parser->lexer, RID_GOTO))
+ /* 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))
+ for (;;)
+ {
+ cp_token *token = cp_lexer_peek_token (parser->lexer);
+ location_t loc = token->location;
+ switch (cp_lexer_peek_token (parser->lexer)->keyword)
+ {
+ case RID_VOLATILE:
+ if (volatile_loc)
+ {
+ error_at (loc, "duplicate asm qualifier %qT", token->u.value);
+ inform (volatile_loc, "first seen here");
+ }
+ else
+ {
+ 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);
+ 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);
+ 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);
+ cp_lexer_consume_token (parser->lexer);
+ continue;
+
+ default:
+ break;
+ }
+ break;
+ }
+
+ bool volatile_p = (volatile_loc != UNKNOWN_LOCATION);
+ bool inline_p = (inline_loc != UNKNOWN_LOCATION);
+ bool goto_p = (goto_loc != UNKNOWN_LOCATION);
+
+ if (!parser->in_function_body && (inline_p || goto_p))
{
- /* Remember that we saw the `goto' keyword. */
- goto_p = true;
- /* Consume the token. */
- cp_lexer_consume_token (parser->lexer);
+ 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;
CPP_CLOSE_PAREN))
clobbers = cp_parser_asm_clobber_list (parser);
}
- else if (goto_p
- && cp_lexer_next_token_is (parser->lexer, CPP_SCOPE))
+ else if (goto_p && cp_lexer_next_token_is (parser->lexer, CPP_SCOPE))
/* The labels are coming next. */
labels_p = true;
if (parser->in_function_body)
{
asm_stmt = finish_asm_stmt (volatile_p, string, outputs,
- inputs, clobbers, labels);
+ inputs, clobbers, labels, inline_p);
/* If the extended syntax was not used, mark the ASM_EXPR. */
if (!extended_p)
{
function-definition:
decl-specifier-seq [opt] declarator function-transaction-block
+ The parser flags FLAGS is used to control type-specifier parsing.
+
The DECL_SPECIFIERS apply to this declarator. Returns a
representation of the entity declared. If MEMBER_P is TRUE, then
this declarator appears in a class scope. The new DECL created by
static tree
cp_parser_init_declarator (cp_parser* parser,
+ cp_parser_flags flags,
cp_decl_specifier_seq *decl_specifiers,
vec<deferred_access_check, va_gc> *checks,
bool function_definition_allowed_p,
/* Parse the declarator. */
declarator
= cp_parser_declarator (parser, CP_PARSER_DECLARATOR_NAMED,
- &ctor_dtor_or_conv_p,
+ flags, &ctor_dtor_or_conv_p,
/*parenthesized_p=*/NULL,
- member_p, friend_p);
+ member_p, friend_p, /*static_p=*/false);
/* Gather up the deferred checks. */
stop_deferring_access_checks ();
attributes [opt] ptr-operator abstract-declarator [opt]
attributes [opt] direct-abstract-declarator
+ The parser flags FLAGS is used to control type-specifier parsing.
+
If CTOR_DTOR_OR_CONV_P is not NULL, *CTOR_DTOR_OR_CONV_P is used to
detect constructors, destructors, deduction guides, or conversion operators.
It is set to -1 if the declarator is a name, and +1 if it is a
MEMBER_P is true iff this declarator is a member-declarator.
- FRIEND_P is true iff this declarator is a friend. */
+ FRIEND_P is true iff this declarator is a friend.
+
+ STATIC_P is true iff the keyword static was seen. */
static cp_declarator *
cp_parser_declarator (cp_parser* parser,
cp_parser_declarator_kind dcl_kind,
+ cp_parser_flags flags,
int* ctor_dtor_or_conv_p,
bool* parenthesized_p,
- bool member_p, bool friend_p)
+ bool member_p, bool friend_p, bool static_p)
{
cp_declarator *declarator;
enum tree_code code;
/* Parse the dependent declarator. */
declarator = cp_parser_declarator (parser, dcl_kind,
+ CP_PARSER_FLAGS_NONE,
/*ctor_dtor_or_conv_p=*/NULL,
/*parenthesized_p=*/NULL,
/*member_p=*/false,
- friend_p);
+ friend_p, /*static_p=*/false);
/* If we are parsing an abstract-declarator, we must handle the
case where the dependent declarator is absent. */
*parenthesized_p = cp_lexer_next_token_is (parser->lexer,
CPP_OPEN_PAREN);
declarator = cp_parser_direct_declarator (parser, dcl_kind,
- ctor_dtor_or_conv_p,
- member_p, friend_p);
+ flags, ctor_dtor_or_conv_p,
+ member_p, friend_p, static_p);
}
if (gnu_attributes && declarator && declarator != cp_error_declarator)
we are parsing a direct-declarator. It is
CP_PARSER_DECLARATOR_EITHER, if we can accept either - in the case
of ambiguity we prefer an abstract declarator, as per
- [dcl.ambig.res]. CTOR_DTOR_OR_CONV_P, MEMBER_P, and FRIEND_P are
+ [dcl.ambig.res].
+ The parser flags FLAGS is used to control type-specifier parsing.
+ CTOR_DTOR_OR_CONV_P, MEMBER_P, FRIEND_P, and STATIC_P are
as for cp_parser_declarator. */
static cp_declarator *
cp_parser_direct_declarator (cp_parser* parser,
cp_parser_declarator_kind dcl_kind,
+ cp_parser_flags flags,
int* ctor_dtor_or_conv_p,
- bool member_p, bool friend_p)
+ bool member_p, bool friend_p, bool static_p)
{
cp_token *token;
cp_declarator *declarator = NULL;
begin_scope (sk_function_parms, NULL_TREE);
/* Parse the parameter-declaration-clause. */
- params = cp_parser_parameter_declaration_clause (parser);
+ params
+ = cp_parser_parameter_declaration_clause (parser, flags);
/* Consume the `)'. */
parens.require_close (parser);
tree attrs;
bool memfn = (member_p || (pushed_scope
&& CLASS_TYPE_P (pushed_scope)));
+ unsigned char local_variables_forbidden_p
+ = parser->local_variables_forbidden_p;
+ /* 'this' is not allowed in static member functions. */
+ if (static_p || friend_p)
+ parser->local_variables_forbidden_p |= THIS_FORBIDDEN;
is_declarator = true;
return type, so are not those of the declared
function. */
parser->default_arg_ok_p = false;
+
+ /* Restore the state of local_variables_forbidden_p. */
+ parser->local_variables_forbidden_p
+ = local_variables_forbidden_p;
}
/* Remove the function parms from scope. */
saved_in_type_id_in_expr_p = parser->in_type_id_in_expr_p;
parser->in_type_id_in_expr_p = true;
declarator
- = cp_parser_declarator (parser, dcl_kind, ctor_dtor_or_conv_p,
+ = cp_parser_declarator (parser, dcl_kind, flags,
+ ctor_dtor_or_conv_p,
/*parenthesized_p=*/NULL,
- member_p, friend_p);
+ member_p, friend_p,
+ /*static_p=*/false);
parser->in_type_id_in_expr_p = saved_in_type_id_in_expr_p;
first = false;
/* Expect a `)'. */
}
declarator = make_id_declarator (qualifying_scope,
unqualified_name,
- sfk);
+ sfk, token->location);
declarator->std_attributes = attrs;
- declarator->id_loc = token->location;
declarator->parameter_pack_p = pack_expansion_p;
if (pack_expansion_p)
maybe_warn_variadic_templates ();
+
+ /* We're looking for this case in [temp.res]:
+ A qualified-id is assumed to name a type if [...]
+ - it is a decl-specifier of the decl-specifier-seq of a
+ parameter-declaration in a declarator of a function or
+ function template declaration, ... */
+ if (cxx_dialect >= cxx2a
+ && (flags & CP_PARSER_FLAGS_TYPENAME_OPTIONAL)
+ && declarator->kind == cdk_id
+ && !at_class_scope_p ()
+ && cp_lexer_next_token_is (parser->lexer, CPP_OPEN_PAREN))
+ {
+ /* ...whose declarator-id is qualified. If it isn't, never
+ assume the parameters to refer to types. */
+ if (qualifying_scope == NULL_TREE)
+ flags &= ~CP_PARSER_FLAGS_TYPENAME_OPTIONAL;
+ else
+ {
+ /* Now we have something like
+ template <typename T> int C::x(S::p);
+ which can be a function template declaration or a
+ variable template definition. If name lookup for
+ the declarator-id C::x finds one or more function
+ templates, assume S::p to name a type. Otherwise,
+ don't. */
+ tree decl
+ = cp_parser_lookup_name_simple (parser, unqualified_name,
+ token->location);
+ if (!is_overloaded_fn (decl))
+ flags &= ~CP_PARSER_FLAGS_TYPENAME_OPTIONAL;
+ }
+ }
}
handle_declarator:;
type-id:
type-specifier-seq abstract-declarator [opt]
+ The parser flags FLAGS is used to control type-specifier parsing.
+
+ If IS_TEMPLATE_ARG is true, we are parsing a template argument.
+
+ If IS_TRAILING_RETURN is true, we are in a trailing-return-type,
+ i.e. we've just seen "->".
+
Returns the TYPE specified. */
static tree
-cp_parser_type_id_1 (cp_parser* parser, bool is_template_arg,
- bool is_trailing_return)
+cp_parser_type_id_1 (cp_parser *parser, cp_parser_flags flags,
+ bool is_template_arg, bool is_trailing_return,
+ location_t *type_location)
{
cp_decl_specifier_seq type_specifier_seq;
cp_declarator *abstract_declarator;
/* Parse the type-specifier-seq. */
- cp_parser_type_specifier_seq (parser, /*is_declaration=*/false,
+ cp_parser_type_specifier_seq (parser, flags,
+ /*is_declaration=*/false,
is_trailing_return,
&type_specifier_seq);
+ if (type_location)
+ *type_location = type_specifier_seq.locations[ds_type_spec];
+
if (is_template_arg && type_specifier_seq.type
&& TREE_CODE (type_specifier_seq.type) == TEMPLATE_TYPE_PARM
&& CLASS_PLACEHOLDER_TEMPLATE (type_specifier_seq.type))
cp_parser_parse_tentatively (parser);
/* Look for the declarator. */
abstract_declarator
- = cp_parser_declarator (parser, CP_PARSER_DECLARATOR_ABSTRACT, NULL,
+ = cp_parser_declarator (parser, CP_PARSER_DECLARATOR_ABSTRACT,
+ CP_PARSER_FLAGS_NONE, NULL,
/*parenthesized_p=*/NULL,
/*member_p=*/false,
- /*friend_p=*/false);
+ /*friend_p=*/false,
+ /*static_p=*/false);
/* Check to see if there really was a declarator. */
if (!cp_parser_parse_definitely (parser))
abstract_declarator = NULL;
is_template_arg);
}
+/* Wrapper for cp_parser_type_id_1. */
+
static tree
-cp_parser_type_id (cp_parser *parser)
+cp_parser_type_id (cp_parser *parser, cp_parser_flags flags,
+ location_t *type_location)
{
- return cp_parser_type_id_1 (parser, false, false);
+ return cp_parser_type_id_1 (parser, flags, false, false, type_location);
}
+/* Wrapper for cp_parser_type_id_1. */
+
static tree
cp_parser_template_type_arg (cp_parser *parser)
{
const char *saved_message = parser->type_definition_forbidden_message;
parser->type_definition_forbidden_message
= G_("types may not be defined in template arguments");
- r = cp_parser_type_id_1 (parser, true, false);
+ r = cp_parser_type_id_1 (parser, CP_PARSER_FLAGS_NONE, true, false, NULL);
parser->type_definition_forbidden_message = saved_message;
if (cxx_dialect >= cxx14 && !flag_concepts && type_uses_auto (r))
{
return r;
}
+/* Wrapper for cp_parser_type_id_1. */
+
static tree
cp_parser_trailing_type_id (cp_parser *parser)
{
- return cp_parser_type_id_1 (parser, false, true);
+ return cp_parser_type_id_1 (parser, CP_PARSER_FLAGS_TYPENAME_OPTIONAL,
+ false, true, NULL);
}
/* Parse a type-specifier-seq.
type-specifier-seq:
attributes type-specifier-seq [opt]
+ The parser flags FLAGS is used to control type-specifier parsing.
+
If IS_DECLARATION is true, we are at the start of a "condition" or
exception-declaration, so we might be followed by a declarator-id.
static void
cp_parser_type_specifier_seq (cp_parser* parser,
+ cp_parser_flags flags,
bool is_declaration,
bool is_trailing_return,
cp_decl_specifier_seq *type_specifier_seq)
{
bool seen_type_specifier = false;
- cp_parser_flags flags = CP_PARSER_FLAGS_OPTIONAL;
cp_token *start_token = NULL;
/* Clear the TYPE_SPECIFIER_SEQ. */
clear_decl_specs (type_specifier_seq);
+ flags |= CP_PARSER_FLAGS_OPTIONAL;
/* In the context of a trailing return type, enum E { } is an
elaborated-type-specifier followed by a function-body, not an
enum-specifier. */
parameter-declaration-list [opt] ... [opt]
parameter-declaration-list , ...
+ The parser flags FLAGS is used to control type-specifier parsing.
+
Returns a representation for the parameter declarations. A return
value of NULL indicates a parameter-declaration-clause consisting
only of an ellipsis. */
static tree
-cp_parser_parameter_declaration_clause (cp_parser* parser)
+cp_parser_parameter_declaration_clause (cp_parser* parser,
+ cp_parser_flags flags)
{
tree parameters;
cp_token *token;
}
else if (token->type == CPP_CLOSE_PAREN)
/* There are no parameters. */
- {
-#ifndef NO_IMPLICIT_EXTERN_C
- if (in_system_header_at (input_location)
- && current_class_type == NULL
- && current_lang_name == lang_name_c)
- return NULL_TREE;
- else
-#endif
- return void_list_node;
- }
+ return void_list_node;
/* Check for `(void)', too, which is a special case. */
else if (token->keyword == RID_VOID
&& (cp_lexer_peek_nth_token (parser->lexer, 2)->type
}
/* Parse the parameter-declaration-list. */
- parameters = cp_parser_parameter_declaration_list (parser);
+ parameters = cp_parser_parameter_declaration_list (parser, flags);
/* If a parse error occurred while parsing the
parameter-declaration-list, then the entire
parameter-declaration-clause is erroneous. */
parameter-declaration
parameter-declaration-list , parameter-declaration
+ The parser flags FLAGS is used to control type-specifier parsing.
+
Returns a representation of the parameter-declaration-list, as for
cp_parser_parameter_declaration_clause. However, the
`void_list_node' is never appended to the list. */
static tree
-cp_parser_parameter_declaration_list (cp_parser* parser)
+cp_parser_parameter_declaration_list (cp_parser* parser, cp_parser_flags flags)
{
tree parameters = NULL_TREE;
tree *tail = ¶meters;
/* Parse the parameter. */
parameter
- = cp_parser_parameter_declaration (parser,
+ = cp_parser_parameter_declaration (parser, flags,
/*template_parm_p=*/false,
&parenthesized_p);
decl-specifier-seq ... [opt] abstract-declarator [opt]
decl-specifier-seq abstract-declarator [opt] = assignment-expression
+ The parser flags FLAGS is used to control type-specifier parsing.
+
If TEMPLATE_PARM_P is TRUE, then this parameter-declaration
declares a template parameter. (In that case, a non-nested `>'
token encountered during the parsing of the assignment-expression
static cp_parameter_declarator *
cp_parser_parameter_declaration (cp_parser *parser,
+ cp_parser_flags flags,
bool template_parm_p,
bool *parenthesized_p)
{
/* Parse the declaration-specifiers. */
cp_token *decl_spec_token_start = cp_lexer_peek_token (parser->lexer);
cp_parser_decl_specifier_seq (parser,
- CP_PARSER_FLAGS_NONE,
+ flags,
&decl_specifiers,
&declares_class_or_enum);
declarator_token_start = token;
declarator = cp_parser_declarator (parser,
CP_PARSER_DECLARATOR_EITHER,
+ CP_PARSER_FLAGS_NONE,
/*ctor_dtor_or_conv_p=*/NULL,
parenthesized_p,
/*member_p=*/false,
- /*friend_p=*/false);
+ /*friend_p=*/false,
+ /*static_p=*/false);
parser->default_arg_ok_p = saved_default_arg_ok_p;
/* After the declarator, allow more attributes. */
decl_specifiers.attributes
parameter was introduced during cp_parser_parameter_declaration,
change any implicit parameters introduced into packs. */
if (parser->implicit_template_parms
- && (token->type == CPP_ELLIPSIS
+ && ((token->type == CPP_ELLIPSIS
+ && declarator_can_be_parameter_pack (declarator))
|| (declarator && declarator->parameter_pack_p)))
{
int latest_template_parm_idx = TREE_VEC_LENGTH
else
default_argument = NULL_TREE;
+ if (default_argument)
+ STRIP_ANY_LOCATION_WRAPPER (default_argument);
+
/* Generate a location for the parameter, ranging from the start of the
initial token to the end of the final token (using input_location for
the latter, set up by cp_lexer_set_source_position_from_token when
{
tree default_argument = NULL_TREE;
bool saved_greater_than_is_operator_p;
- bool saved_local_variables_forbidden_p;
+ unsigned char saved_local_variables_forbidden_p;
bool non_constant_p, is_direct_init;
/* Make sure that PARSER->GREATER_THAN_IS_OPERATOR_P is
/* Local variable names (and the `this' keyword) may not
appear in a default argument. */
saved_local_variables_forbidden_p = parser->local_variables_forbidden_p;
- parser->local_variables_forbidden_p = true;
+ parser->local_variables_forbidden_p = LOCAL_VARS_AND_THIS_FORBIDDEN;
/* Parse the assignment-expression. */
if (template_parm_p)
push_deferring_access_checks (dk_no_deferred);
bool in_function_try_block)
{
tree body, list;
- const bool check_body_p =
- DECL_CONSTRUCTOR_P (current_function_decl)
- && DECL_DECLARED_CONSTEXPR_P (current_function_decl);
+ const bool check_body_p
+ = (DECL_CONSTRUCTOR_P (current_function_decl)
+ && DECL_DECLARED_CONSTEXPR_P (current_function_decl));
tree last = NULL;
+ if (in_function_try_block
+ && DECL_DECLARED_CONSTEXPR_P (current_function_decl)
+ && cxx_dialect < cxx2a)
+ {
+ if (DECL_CONSTRUCTOR_P (current_function_decl))
+ pedwarn (input_location, 0,
+ "function-try-block body of %<constexpr%> constructor only "
+ "available with %<-std=c++2a%> or %<-std=gnu++2a%>");
+ else
+ pedwarn (input_location, 0,
+ "function-try-block body of %<constexpr%> function only "
+ "available with %<-std=c++2a%> or %<-std=gnu++2a%>");
+ }
+
/* Begin the function body. */
body = begin_function_body ();
/* Parse the optional ctor-initializer. */
/* If it's not a `}', then there is a non-trivial initializer. */
if (cp_lexer_next_token_is_not (parser->lexer, CPP_CLOSE_BRACE))
{
+ bool designated;
/* Parse the initializer list. */
CONSTRUCTOR_ELTS (initializer)
- = cp_parser_initializer_list (parser, non_constant_p);
+ = cp_parser_initializer_list (parser, non_constant_p, &designated);
+ CONSTRUCTOR_IS_DESIGNATED_INIT (initializer) = designated;
/* A trailing `,' token is allowed. */
if (cp_lexer_next_token_is (parser->lexer, CPP_COMMA))
cp_lexer_consume_token (parser->lexer);
switch (token->type)
{
- case CPP_EOF:
case CPP_PRAGMA_EOL:
+ if (!parser->lexer->in_pragma)
+ break;
+ /* FALLTHRU */
+ case CPP_EOF:
/* If we've run out of tokens, then there is no closing `]'. */
return false;
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 (EXPR_LOC_OR_LOC (val, input_location),
+ error_at (cp_expr_loc_or_loc (val, input_location),
"%<.%s%> designator used multiple times in "
"the same initializer list",
IDENTIFIER_POINTER (designator));
- (*v)[i].index = NULL_TREE;
+ (*v)[i].index = error_mark_node;
}
else
IDENTIFIER_MARKED (designator) = 1;
IDENTIFIER_MARKED (designator) = 0;
}
+ *designated = first_designator != NULL_TREE;
return v;
}
decl = cp_parser_maybe_treat_template_as_class (decl, class_head_p);
/* If this is a typename, create a TYPENAME_TYPE. */
- if (typename_p && decl != error_mark_node)
+ if (typename_p
+ && decl != error_mark_node
+ && !is_overloaded_fn (decl))
{
decl = make_typename_type (scope, decl, typename_type,
/*complain=*/tf_error);
cp_ensure_no_oacc_routine (parser);
/* Issue an error message if type-definitions are forbidden here. */
- cp_parser_check_type_definition (parser);
+ bool type_definition_ok_p = cp_parser_check_type_definition (parser);
/* Remember that we are defining one more class. */
++parser->num_classes_being_defined;
/* Inside the class, surrounding template-parameter-lists do not
cp_default_arg_entry *e;
tree save_ccp, save_ccr;
- if (any_erroneous_template_args_p (type))
+ if (!type_definition_ok_p || any_erroneous_template_args_p (type))
{
/* Skip default arguments, NSDMIs, etc, in order to improve
error recovery (c++/71169, c++/71832). */
cp_parser_check_class_key (class_key, type);
/* If this type was already complete, and we see another definition,
- that's an error. */
- if (type != error_mark_node && COMPLETE_TYPE_P (type))
+ that's an error. Likewise if the type is already being defined:
+ this can happen, eg, when it's defined from within an expression
+ (c++/84605). */
+ if (type != error_mark_node
+ && (COMPLETE_TYPE_P (type) || TYPE_BEING_DEFINED (type)))
{
error_at (type_start_token->location, "redefinition of %q#T",
type);
by the standard until C++17. */
pedwarn (token->location, OPT_Wpedantic,
"ISO C++ forbids typename key in template template parameter;"
- " use -std=c++17 or -std=gnu++17");
+ " use %<-std=c++17%> or %<-std=gnu++17%>");
}
else
cp_parser_error (parser, "expected %<class%> or %<typename%>");
/* Parse the decl-specifier-seq. */
decl_spec_token_start = cp_lexer_peek_token (parser->lexer);
cp_parser_decl_specifier_seq (parser,
- CP_PARSER_FLAGS_OPTIONAL,
+ (CP_PARSER_FLAGS_OPTIONAL
+ | CP_PARSER_FLAGS_TYPENAME_OPTIONAL),
&decl_specifiers,
&declares_class_or_enum);
/* Check for an invalid type-name. */
tree identifier;
tree width;
tree late_attributes = NULL_TREE;
+ location_t id_location
+ = cp_lexer_peek_token (parser->lexer)->location;
if (named_bitfld)
identifier = cp_parser_identifier (parser);
&& 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)
decl = grokbitfield (identifier
? make_id_declarator (NULL_TREE,
identifier,
- sfk_none)
+ sfk_none,
+ id_location)
: NULL,
&decl_specifiers,
width, initializer,
cp_declarator *declarator;
tree asm_specification;
int ctor_dtor_or_conv_p;
+ bool static_p = (decl_specifiers.storage_class == sc_static);
/* Parse the declarator. */
declarator
= cp_parser_declarator (parser, CP_PARSER_DECLARATOR_NAMED,
+ CP_PARSER_FLAGS_TYPENAME_OPTIONAL,
&ctor_dtor_or_conv_p,
/*parenthesized_p=*/NULL,
/*member_p=*/true,
- friend_p);
+ friend_p, static_p);
/* If something went wrong parsing the declarator, make sure
that we at least consume some tokens. */
matching_parens parens;
parens.consume_open (parser);
+ tree save_ccp = current_class_ptr;
+ tree save_ccr = current_class_ref;
+
+ if (current_class_type)
+ inject_this_parameter (current_class_type, TYPE_UNQUALIFIED);
+
if (require_constexpr)
{
/* Types may not be defined in an exception-specification. */
parser->type_definition_forbidden_message
= G_("types may not be defined in an exception-specification");
- expr = cp_parser_constant_expression (parser);
+ bool non_constant_p;
+ expr
+ = cp_parser_constant_expression (parser,
+ /*allow_non_constant=*/true,
+ &non_constant_p);
+ if (non_constant_p
+ && !require_potential_rvalue_constant_expression (expr))
+ {
+ expr = NULL_TREE;
+ return_cond = true;
+ }
/* Restore the saved message. */
parser->type_definition_forbidden_message = saved_message;
}
parens.require_close (parser);
+
+ current_class_ptr = save_ccp;
+ current_class_ref = save_ccr;
}
else
{
cp_parser_require_keyword (parser, RID_TRY, RT_TRY);
if (parser->in_function_body
- && DECL_DECLARED_CONSTEXPR_P (current_function_decl))
- error ("%<try%> in %<constexpr%> function");
+ && DECL_DECLARED_CONSTEXPR_P (current_function_decl)
+ && cxx_dialect < cxx2a)
+ pedwarn (input_location, 0,
+ "%<try%> in %<constexpr%> function only "
+ "available with %<-std=c++2a%> or %<-std=gnu++2a%>");
try_block = begin_try_block ();
cp_parser_compound_statement (parser, NULL, BCS_TRY_BLOCK, false);
= G_("types may not be defined in exception-declarations");
/* Parse the type-specifier-seq. */
- cp_parser_type_specifier_seq (parser, /*is_declaration=*/true,
+ cp_parser_type_specifier_seq (parser, CP_PARSER_FLAGS_NONE,
+ /*is_declaration=*/true,
/*is_trailing_return=*/false,
&type_specifiers);
/* If it's a `)', then there is no declarator. */
declarator = NULL;
else
declarator = cp_parser_declarator (parser, CP_PARSER_DECLARATOR_EITHER,
+ CP_PARSER_FLAGS_NONE,
/*ctor_dtor_or_conv_p=*/NULL,
/*parenthesized_p=*/NULL,
/*member_p=*/false,
- /*friend_p=*/false);
+ /*friend_p=*/false,
+ /*static_p=*/false);
/* Restore the saved message. */
parser->type_definition_forbidden_message = saved_message;
cp_lexer_consume_token (parser->lexer);
/* Look for the two `(' tokens. */
matching_parens outer_parens;
- outer_parens.require_open (parser);
+ if (!outer_parens.require_open (parser))
+ ok = false;
matching_parens inner_parens;
- inner_parens.require_open (parser);
+ if (!inner_parens.require_open (parser))
+ ok = false;
/* Peek at the next token. */
token = cp_lexer_peek_token (parser->lexer);
the arguments, if any. */
static tree
-cp_parser_gnu_attribute_list (cp_parser* parser)
+cp_parser_gnu_attribute_list (cp_parser* parser, bool exactly_one /* = false */)
{
tree attribute_list = NULL_TREE;
bool save_translate_strings_p = parser->translate_strings_p;
+ /* Don't create wrapper nodes within attributes: the
+ handlers don't know how to handle them. */
+ auto_suppress_location_wrappers sentinel;
+
parser->translate_strings_p = false;
while (true)
{
token = cp_lexer_peek_token (parser->lexer);
}
- /* Now, look for more attributes. If the next token isn't a
- `,', we're done. */
- if (token->type != CPP_COMMA)
+ /* Unless EXACTLY_ONE is set look for more attributes.
+ If the next token isn't a `,', we're done. */
+ if (exactly_one || token->type != CPP_COMMA)
break;
/* Consume the comma and keep going. */
return error_mark_node;
}
+ attr_ns = canonicalize_attr_name (attr_ns);
attr_id = canonicalize_attr_name (attr_id);
attribute = build_tree_list (build_tree_list (attr_ns, attr_id),
NULL_TREE);
token = cp_lexer_peek_token (parser->lexer);
}
else if (attr_ns)
- attribute = build_tree_list (build_tree_list (attr_ns, attr_id),
- NULL_TREE);
+ {
+ attr_ns = canonicalize_attr_name (attr_ns);
+ attr_id = canonicalize_attr_name (attr_id);
+ attribute = build_tree_list (build_tree_list (attr_ns, attr_id),
+ NULL_TREE);
+ }
else
{
attr_id = canonicalize_attr_name (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)) = get_identifier ("gnu");
+ TREE_PURPOSE (TREE_PURPOSE (attribute)) = gnu_identifier;
/* C++14 deprecated attribute is equivalent to GNU's. */
else if (is_attribute_p ("deprecated", attr_id))
- TREE_PURPOSE (TREE_PURPOSE (attribute)) = get_identifier ("gnu");
+ TREE_PURPOSE (TREE_PURPOSE (attribute)) = gnu_identifier;
/* C++17 fallthrough attribute is equivalent to GNU's. */
else if (is_attribute_p ("fallthrough", attr_id))
- TREE_PURPOSE (TREE_PURPOSE (attribute)) = get_identifier ("gnu");
+ TREE_PURPOSE (TREE_PURPOSE (attribute)) = gnu_identifier;
/* Transactional Memory TS optimize_for_synchronized attribute is
equivalent to GNU transaction_callable. */
else if (is_attribute_p ("optimize_for_synchronized", attr_id))
vec<tree, va_gc> *vec;
int attr_flag = normal_attr;
- if (attr_ns == get_identifier ("gnu")
+ if (attr_ns == gnu_identifier
&& attribute_takes_identifier_p (attr_id))
/* A GNU attribute that takes an identifier in parameter. */
attr_flag = id_attr;
&& !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);
|| !cp_parser_require (parser, CPP_CLOSE_SQUARE, RT_CLOSE_SQUARE))
cp_parser_skip_to_end_of_statement (parser);
else
- /* Warn about parsing c++11 attribute in non-c++1 mode, only
+ /* Warn about parsing c++11 attribute in non-c++11 mode, only
when we are sure that we have actually parsed them. */
maybe_warn_cpp0x (CPP0X_ATTRIBUTES);
}
/* Build the C++-11 representation of an 'aligned'
attribute. */
- attributes =
- build_tree_list (build_tree_list (get_identifier ("gnu"),
- get_identifier ("aligned")),
- alignas_expr);
+ attributes
+ = build_tree_list (build_tree_list (gnu_identifier,
+ aligned_identifier), alignas_expr);
}
return attributes;
tree attr_specs = NULL_TREE;
tree attr_last = NULL_TREE;
+ /* Don't create wrapper nodes within attributes: the
+ handlers don't know how to handle them. */
+ auto_suppress_location_wrappers sentinel;
+
while (true)
{
tree attr_spec = cp_parser_std_attribute_spec (parser);
do
switch (cp_lexer_peek_nth_token (parser->lexer, n++)->type)
{
- case CPP_EOF:
case CPP_PRAGMA_EOL:
+ if (!parser->lexer->in_pragma)
+ break;
+ /* FALLTHRU */
+ case CPP_EOF:
/* Ran out of tokens. */
return orig_n;
case CPP_OPEN_PAREN:
&& tok->u.value == ridpointers[RID_REQUIRES])
{
error_at (cp_lexer_peek_token (parser->lexer)->location,
- "%<requires%> only available with -fconcepts");
+ "%<requires%> only available with %<-fconcepts%>");
/* Parse and discard the requires-clause. */
cp_lexer_consume_token (parser->lexer);
cp_parser_requires_clause (parser);
if (!parens.require_open (parser))
return error_mark_node;
- tree parms = cp_parser_parameter_declaration_clause (parser);
+ tree parms
+ = cp_parser_parameter_declaration_clause (parser, CP_PARSER_FLAGS_NONE);
if (!parens.require_close (parser))
return error_mark_node;
/*type_p=*/false,
/*is_declaration=*/false));
+ /* Resolve the TYPENAME_TYPE, because the call above didn't do it. */
+ if (nested_name_specifier
+ && TREE_CODE (nested_name_specifier) == TYPENAME_TYPE)
+ {
+ tree s = resolve_typename_type (nested_name_specifier,
+ /*only_current_p=*/false);
+ if (TREE_CODE (s) != TYPENAME_TYPE)
+ nested_name_specifier = s;
+ }
+
outside_class_specifier_p = (!at_class_scope_p ()
|| !TYPE_BEING_DEFINED (current_class_type)
|| friend_p);
{
tree parm_list = TREE_VEC_ELT (parameter_list, 0);
tree parm = INNERMOST_TEMPLATE_PARMS (parm_list);
- if (TREE_TYPE (parm) != char_type_node
- || !TEMPLATE_PARM_PARAMETER_PACK (DECL_INITIAL (parm)))
+ if (CLASS_TYPE_P (TREE_TYPE (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. */;
+ else if (TREE_TYPE (parm) != char_type_node
+ || !TEMPLATE_PARM_PARAMETER_PACK (DECL_INITIAL (parm)))
ok = false;
}
else if (num_parms == 2 && cxx_dialect >= cxx14)
|| TREE_TYPE (parm) != TREE_TYPE (type)
|| !TEMPLATE_PARM_PARAMETER_PACK (DECL_INITIAL (parm)))
ok = false;
+ else
+ /* http://cplusplus.github.io/EWG/ewg-active.html#66 */
+ pedwarn (DECL_SOURCE_LOCATION (decl), OPT_Wpedantic,
+ "ISO C++ did not adopt string literal operator templa"
+ "tes taking an argument pack of characters");
}
else
ok = false;
}
if (!ok)
{
- if (cxx_dialect >= cxx14)
- error ("literal operator template %qD has invalid parameter list."
- " Expected non-type template argument pack <char...>"
- " or <typename CharT, CharT...>",
+ 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);
else
error ("literal operator template %qD has invalid parameter list."
- " Expected non-type template argument pack <char...>",
+ " Expected non-type template parameter pack <char...>",
decl);
}
}
matching identifiers. */
tree introduction_list = cp_parser_introduction_list (parser);
+ /* Look for closing brace for introduction. */
+ if (!braces.require_close (parser))
+ return true;
+
/* The introduction-list shall not be empty. */
int nargs = TREE_VEC_LENGTH (introduction_list);
if (nargs == 0)
{
- error ("empty introduction-list");
+ /* In cp_parser_introduction_list we have already issued an error. */
return true;
}
- /* Look for closing brace for introduction. */
- if (!braces.require_close (parser))
- return true;
-
if (tmpl_decl == error_mark_node)
{
cp_parser_name_lookup_error (parser, concept_name, tmpl_decl, NLE_NULL,
alternative. */
decl_spec_token_start = cp_lexer_peek_token (parser->lexer);
cp_parser_decl_specifier_seq (parser,
- CP_PARSER_FLAGS_OPTIONAL,
+ (CP_PARSER_FLAGS_OPTIONAL
+ | CP_PARSER_FLAGS_TYPENAME_OPTIONAL),
&decl_specifiers,
&declares_class_or_enum);
if (friend_p)
|| decl_specifiers.type != error_mark_node))
{
decl = cp_parser_init_declarator (parser,
+ CP_PARSER_FLAGS_TYPENAME_OPTIONAL,
&decl_specifiers,
checks,
/*function_definition_allowed_p=*/true,
tree saved_qualifying_scope;
tree saved_object_scope;
bool saved_greater_than_is_operator_p;
- int saved_unevaluated_operand;
- int saved_inhibit_evaluation_warnings;
/* [temp.names]
saved_object_scope = parser->object_scope;
/* We need to evaluate the template arguments, even though this
template-id may be nested within a "sizeof". */
- saved_unevaluated_operand = cp_unevaluated_operand;
- cp_unevaluated_operand = 0;
- saved_inhibit_evaluation_warnings = c_inhibit_evaluation_warnings;
- c_inhibit_evaluation_warnings = 0;
+ cp_evaluated ev;
/* Parse the template-argument-list itself. */
if (cp_lexer_next_token_is (parser->lexer, CPP_GREATER)
|| cp_lexer_next_token_is (parser->lexer, CPP_RSHIFT))
parser->scope = saved_scope;
parser->qualifying_scope = saved_qualifying_scope;
parser->object_scope = saved_object_scope;
- cp_unevaluated_operand = saved_unevaluated_operand;
- c_inhibit_evaluation_warnings = saved_inhibit_evaluation_warnings;
return arguments;
}
static void
cp_parser_late_parsing_default_args (cp_parser *parser, tree fn)
{
- bool saved_local_variables_forbidden_p;
+ unsigned char saved_local_variables_forbidden_p;
tree parm, parmdecl;
/* While we're parsing the default args, we might (due to the
/* Local variable names (and the `this' keyword) may not appear
in a default argument. */
saved_local_variables_forbidden_p = parser->local_variables_forbidden_p;
- parser->local_variables_forbidden_p = true;
+ parser->local_variables_forbidden_p = LOCAL_VARS_AND_THIS_FORBIDDEN;
push_defarg_context (fn);
/* If all went well, then we're done. */
if (cp_parser_parse_definitely (parser))
- {
- cp_decl_specifier_seq decl_specs;
-
- /* Build a trivial decl-specifier-seq. */
- clear_decl_specs (&decl_specs);
- decl_specs.type = type;
-
- /* Call grokdeclarator to figure out what type this is. */
- expr = grokdeclarator (NULL,
- &decl_specs,
- TYPENAME,
- /*initialized=*/0,
- /*attrlist=*/NULL);
- }
+ expr = type;
}
/* If the type-id production did not work out, then we must be
{
decl_specs->any_specifiers_p = true;
- /* If the user tries to redeclare bool, char16_t, char32_t, or wchar_t
- (with, for example, in "typedef int wchar_t;") we remember that
+ /* If the user tries to redeclare bool, char8_t, char16_t, char32_t, or
+ wchar_t (with, for example, in "typedef int wchar_t;") we remember that
this is what happened. In system headers, we ignore these
declarations so that G++ can work with system headers that are not
C++-safe. */
if (decl_spec_seq_has_spec_p (decl_specs, ds_typedef)
&& !type_definition_p
&& (type_spec == boolean_type_node
+ || type_spec == char8_type_node
|| type_spec == char16_type_node
|| type_spec == char32_type_node
|| type_spec == wchar_type_node)
if (decl_specs == NULL)
return;
- source_location location = token->location;
+ location_t location = token->location;
if (decl_specs->locations[ds] == 0)
{
else if (ds == ds_thread)
{
bool gnu = token_is__thread (token);
+ gcc_rich_location richloc (location);
if (gnu != decl_specs->gnu_thread_keyword_p)
- error_at (location,
- "both %<__thread%> and %<thread_local%> specified");
+ {
+ richloc.add_range (decl_specs->locations[ds_thread]);
+ error_at (&richloc,
+ "both %<__thread%> and %<thread_local%> specified");
+ }
else
{
- gcc_rich_location richloc (location);
richloc.add_fixit_remove ();
error_at (&richloc, "duplicate %qD", token->u.value);
}
int ctor_dtor_or_conv_p;
cp_lexer_consume_token (parser->lexer);
cp_parser_declarator (parser, CP_PARSER_DECLARATOR_NAMED,
+ CP_PARSER_FLAGS_NONE,
&ctor_dtor_or_conv_p,
/*parenthesized_p=*/NULL,
/*member_p=*/true,
- /*friend_p=*/false);
+ /*friend_p=*/false,
+ /*static_p=*/false);
peek = cp_lexer_peek_token (parser->lexer);
if (cp_parser_error_occurred (parser))
break;
{
cp_lexer_consume_token (parser->lexer);
begin_scope (sk_function_parms, NULL_TREE);
- if (cp_parser_parameter_declaration_list (parser)
- == error_mark_node)
+ tree t = cp_parser_parameter_declaration_list
+ (parser, CP_PARSER_FLAGS_NONE);
+ if (t == error_mark_node)
error = true;
pop_bindings_and_leave_scope ();
}
}
/* TODO: parse attributes for tail parameters. */
- parmdecl = cp_parser_parameter_declaration (parser, false, NULL);
+ parmdecl = cp_parser_parameter_declaration (parser, CP_PARSER_FLAGS_NONE,
+ false, NULL);
parm = grokdeclarator (parmdecl->declarator,
&parmdecl->decl_specifiers,
PARM, /*initialized=*/0,
/* Get the name of the bitfield. */
declarator = make_id_declarator (NULL_TREE,
cp_parser_identifier (parser),
- sfk_none);
+ sfk_none, token->location);
eat_colon:
cp_lexer_consume_token (parser->lexer); /* Eat ':'. */
/* Parse the declarator. */
declarator
= cp_parser_declarator (parser, CP_PARSER_DECLARATOR_NAMED,
+ CP_PARSER_FLAGS_NONE,
&ctor_dtor_or_conv_p,
/*parenthesized_p=*/NULL,
/*member_p=*/false,
- /*friend_p=*/false);
+ /*friend_p=*/false,
+ /*static_p=*/false);
}
/* Look for attributes that apply to the ivar. */
{
/* We have "@catch (NSException *exception)" or something
like that. Parse the parameter declaration. */
- parm = cp_parser_parameter_declaration (parser, false, NULL);
+ parm = cp_parser_parameter_declaration (parser, CP_PARSER_FLAGS_NONE,
+ false, NULL);
if (parm == NULL)
parameter_declaration = error_mark_node;
else
/* Parse the declarator. */
declarator = cp_parser_declarator (parser, CP_PARSER_DECLARATOR_NAMED,
- NULL, NULL, false, false);
+ CP_PARSER_FLAGS_NONE,
+ NULL, NULL, false, false, false);
/* Look for attributes that apply to the ivar. */
attributes = cp_parser_attributes_opt (parser);
}
\f
-/* OpenMP 2.5 / 3.0 / 3.1 / 4.0 parsing routines. */
+/* OpenMP 2.5 / 3.0 / 3.1 / 4.0 / 4.5 / 5.0 parsing routines. */
/* Returns name of the next clause.
If the clause is not recognized PRAGMA_OMP_CLAUSE_NONE is returned and
case 'f':
if (!strcmp ("final", p))
result = PRAGMA_OMP_CLAUSE_FINAL;
+ else if (!strcmp ("finalize", p))
+ result = PRAGMA_OACC_CLAUSE_FINALIZE;
else if (!strcmp ("firstprivate", p))
result = PRAGMA_OMP_CLAUSE_FIRSTPRIVATE;
else if (!strcmp ("from", p))
result = PRAGMA_OACC_CLAUSE_HOST;
break;
case 'i':
- if (!strcmp ("inbranch", p))
+ if (!strcmp ("if_present", p))
+ result = PRAGMA_OACC_CLAUSE_IF_PRESENT;
+ else if (!strcmp ("in_reduction", p))
+ result = PRAGMA_OMP_CLAUSE_IN_REDUCTION;
+ else if (!strcmp ("inbranch", p))
result = PRAGMA_OMP_CLAUSE_INBRANCH;
else if (!strcmp ("independent", p))
result = PRAGMA_OACC_CLAUSE_INDEPENDENT;
case 'n':
if (!strcmp ("nogroup", p))
result = PRAGMA_OMP_CLAUSE_NOGROUP;
+ else if (!strcmp ("nontemporal", p))
+ result = PRAGMA_OMP_CLAUSE_NONTEMPORAL;
else if (!strcmp ("notinbranch", p))
result = PRAGMA_OMP_CLAUSE_NOTINBRANCH;
else if (!strcmp ("nowait", p))
result = PRAGMA_OACC_CLAUSE_PRESENT;
else if (!strcmp ("present_or_copy", p)
|| !strcmp ("pcopy", p))
- result = PRAGMA_OACC_CLAUSE_PRESENT_OR_COPY;
+ result = PRAGMA_OACC_CLAUSE_COPY;
else if (!strcmp ("present_or_copyin", p)
|| !strcmp ("pcopyin", p))
- result = PRAGMA_OACC_CLAUSE_PRESENT_OR_COPYIN;
+ result = PRAGMA_OACC_CLAUSE_COPYIN;
else if (!strcmp ("present_or_copyout", p)
|| !strcmp ("pcopyout", p))
- result = PRAGMA_OACC_CLAUSE_PRESENT_OR_COPYOUT;
+ result = PRAGMA_OACC_CLAUSE_COPYOUT;
else if (!strcmp ("present_or_create", p)
|| !strcmp ("pcreate", p))
- result = PRAGMA_OACC_CLAUSE_PRESENT_OR_CREATE;
+ result = PRAGMA_OACC_CLAUSE_CREATE;
else if (!strcmp ("priority", p))
result = PRAGMA_OMP_CLAUSE_PRIORITY;
else if (!strcmp ("proc_bind", p))
result = PRAGMA_OMP_CLAUSE_SCHEDULE;
else if (!strcmp ("sections", p))
result = PRAGMA_OMP_CLAUSE_SECTIONS;
- else if (!strcmp ("self", p))
- result = PRAGMA_OACC_CLAUSE_SELF;
+ else if (!strcmp ("self", p)) /* "self" is a synonym for "host". */
+ result = PRAGMA_OACC_CLAUSE_HOST;
else if (!strcmp ("seq", p))
result = PRAGMA_OACC_CLAUSE_SEQ;
else if (!strcmp ("shared", p))
result = PRAGMA_OMP_CLAUSE_SIMDLEN;
break;
case 't':
- if (!strcmp ("taskgroup", p))
+ if (!strcmp ("task_reduction", p))
+ result = PRAGMA_OMP_CLAUSE_TASK_REDUCTION;
+ else if (!strcmp ("taskgroup", p))
result = PRAGMA_OMP_CLAUSE_TASKGROUP;
else if (!strcmp ("thread_limit", p))
result = PRAGMA_OMP_CLAUSE_THREAD_LIMIT;
{
tree name, decl;
+ if (kind == OMP_CLAUSE_DEPEND)
+ cp_parser_parse_tentatively (parser);
token = cp_lexer_peek_token (parser->lexer);
if (kind != 0
&& current_class_ptr
/*declarator_p=*/false,
/*optional_p=*/false);
if (name == error_mark_node)
- goto skip_comma;
+ {
+ if (kind == OMP_CLAUSE_DEPEND
+ && cp_parser_simulate_error (parser))
+ goto depend_lvalue;
+ goto skip_comma;
+ }
if (identifier_p (name))
decl = cp_parser_lookup_name_simple (parser, name, token->location);
else
decl = name;
if (decl == error_mark_node)
- cp_parser_name_lookup_error (parser, name, decl, NLE_NULL,
- token->location);
+ {
+ if (kind == OMP_CLAUSE_DEPEND
+ && cp_parser_simulate_error (parser))
+ goto depend_lvalue;
+ cp_parser_name_lookup_error (parser, name, decl, NLE_NULL,
+ token->location);
+ }
}
if (decl == error_mark_node)
;
/* FALLTHROUGH. */
case OMP_CLAUSE_DEPEND:
case OMP_CLAUSE_REDUCTION:
+ case OMP_CLAUSE_IN_REDUCTION:
+ case OMP_CLAUSE_TASK_REDUCTION:
while (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_SQUARE))
{
tree low_bound = NULL_TREE, length = NULL_TREE;
{
/* Look for `:'. */
if (!cp_parser_require (parser, CPP_COLON, RT_COLON))
- goto skip_comma;
+ {
+ if (kind == OMP_CLAUSE_DEPEND
+ && cp_parser_simulate_error (parser))
+ goto depend_lvalue;
+ goto skip_comma;
+ }
+ if (kind == OMP_CLAUSE_DEPEND)
+ cp_parser_commit_to_tentative_parse (parser);
if (!cp_lexer_next_token_is (parser->lexer,
CPP_CLOSE_SQUARE))
length = cp_parser_expression (parser);
/* Look for the closing `]'. */
if (!cp_parser_require (parser, CPP_CLOSE_SQUARE,
RT_CLOSE_SQUARE))
- goto skip_comma;
+ {
+ if (kind == OMP_CLAUSE_DEPEND
+ && cp_parser_simulate_error (parser))
+ goto depend_lvalue;
+ goto skip_comma;
+ }
decl = tree_cons (low_bound, length, decl);
}
break;
}
+ if (kind == OMP_CLAUSE_DEPEND)
+ {
+ if (cp_lexer_next_token_is_not (parser->lexer, CPP_COMMA)
+ && cp_lexer_next_token_is_not (parser->lexer, CPP_CLOSE_PAREN)
+ && cp_parser_simulate_error (parser))
+ {
+ depend_lvalue:
+ cp_parser_abort_tentative_parse (parser);
+ decl = cp_parser_assignment_expression (parser, NULL,
+ false, false);
+ }
+ else
+ cp_parser_parse_definitely (parser);
+ }
+
tree u = build_omp_clause (token->location, kind);
OMP_CLAUSE_DECL (u) = decl;
OMP_CLAUSE_CHAIN (u) = list;
copyout ( variable-list )
create ( variable-list )
delete ( variable-list )
- present ( variable-list )
- present_or_copy ( variable-list )
- pcopy ( variable-list )
- present_or_copyin ( variable-list )
- pcopyin ( variable-list )
- present_or_copyout ( variable-list )
- pcopyout ( variable-list )
- present_or_create ( variable-list )
- pcreate ( variable-list ) */
+ present ( variable-list ) */
static tree
cp_parser_oacc_data_clause (cp_parser *parser, pragma_omp_clause c_kind,
switch (c_kind)
{
case PRAGMA_OACC_CLAUSE_COPY:
- kind = GOMP_MAP_FORCE_TOFROM;
+ kind = GOMP_MAP_TOFROM;
break;
case PRAGMA_OACC_CLAUSE_COPYIN:
- kind = GOMP_MAP_FORCE_TO;
+ kind = GOMP_MAP_TO;
break;
case PRAGMA_OACC_CLAUSE_COPYOUT:
- kind = GOMP_MAP_FORCE_FROM;
+ kind = GOMP_MAP_FROM;
break;
case PRAGMA_OACC_CLAUSE_CREATE:
- kind = GOMP_MAP_FORCE_ALLOC;
+ kind = GOMP_MAP_ALLOC;
break;
case PRAGMA_OACC_CLAUSE_DELETE:
- kind = GOMP_MAP_DELETE;
+ kind = GOMP_MAP_RELEASE;
break;
case PRAGMA_OACC_CLAUSE_DEVICE:
kind = GOMP_MAP_FORCE_TO;
kind = GOMP_MAP_DEVICE_RESIDENT;
break;
case PRAGMA_OACC_CLAUSE_HOST:
- case PRAGMA_OACC_CLAUSE_SELF:
kind = GOMP_MAP_FORCE_FROM;
break;
case PRAGMA_OACC_CLAUSE_LINK:
case PRAGMA_OACC_CLAUSE_PRESENT:
kind = GOMP_MAP_FORCE_PRESENT;
break;
- case PRAGMA_OACC_CLAUSE_PRESENT_OR_COPY:
- kind = GOMP_MAP_TOFROM;
- break;
- case PRAGMA_OACC_CLAUSE_PRESENT_OR_COPYIN:
- kind = GOMP_MAP_TO;
- break;
- case PRAGMA_OACC_CLAUSE_PRESENT_OR_COPYOUT:
- kind = GOMP_MAP_FROM;
- break;
- case PRAGMA_OACC_CLAUSE_PRESENT_OR_CREATE:
- kind = GOMP_MAP_ALLOC;
- break;
default:
gcc_unreachable ();
}
return list;
}
-/* OpenACC 2.0:
+/* OpenACC 2.5:
auto
+ finalize
independent
nohost
seq */
static tree
-cp_parser_oacc_simple_clause (cp_parser * /* parser */,
- enum omp_clause_code code,
- tree list, location_t location)
+cp_parser_oacc_simple_clause (location_t loc, enum omp_clause_code code,
+ tree list)
{
- check_no_duplicate_clause (list, code, omp_clause_code_name[code], location);
- tree c = build_omp_clause (location, code);
+ check_no_duplicate_clause (list, code, omp_clause_code_name[code], loc);
+
+ tree c = build_omp_clause (loc, code);
OMP_CLAUSE_CHAIN (c) = list;
+
return c;
}
*/
static tree
-cp_parser_oacc_shape_clause (cp_parser *parser, omp_clause_code kind,
+cp_parser_oacc_shape_clause (cp_parser *parser, location_t loc,
+ omp_clause_code kind,
const char *str, tree list)
{
const char *id = "num";
cp_lexer *lexer = parser->lexer;
tree ops[2] = { NULL_TREE, NULL_TREE }, c;
- location_t loc = cp_lexer_peek_token (lexer)->location;
if (kind == OMP_CLAUSE_VECTOR)
id = "length";
if (args == NULL || args->length () == 0)
{
- cp_parser_error (parser, "expected integer expression before ')'");
if (args != NULL)
- release_tree_vector (args);
+ {
+ cp_parser_error (parser, "expected integer expression list");
+ release_tree_vector (args);
+ }
return list;
}
}
/* OpenACC:
- wait ( int-expr-list ) */
+ wait [( int-expr-list )] */
static tree
cp_parser_oacc_clause_wait (cp_parser *parser, tree list)
{
location_t location = cp_lexer_peek_token (parser->lexer)->location;
- if (cp_lexer_peek_token (parser->lexer)->type != CPP_OPEN_PAREN)
- return list;
+ if (cp_lexer_peek_token (parser->lexer)->type == CPP_OPEN_PAREN)
+ list = cp_parser_oacc_wait_list (parser, location, list);
+ else
+ {
+ tree c = build_omp_clause (location, OMP_CLAUSE_WAIT);
- list = cp_parser_oacc_wait_list (parser, location, list);
+ OMP_CLAUSE_DECL (c) = build_int_cst (integer_type_node, GOMP_ASYNC_NOVAL);
+ OMP_CLAUSE_CHAIN (c) = list;
+ list = c;
+ }
return list;
}
if (!parens.require_open (parser))
return list;
- t = cp_parser_condition (parser);
+ t = cp_parser_assignment_expression (parser);
if (t == error_mark_node
|| !parens.require_close (parser))
directive-name-modifier:
parallel | task | taskloop | target data | target | target update
- | target enter data | target exit data */
+ | target enter data | target exit data
+
+ OpenMP 5.0:
+ directive-name-modifier:
+ ... | simd | cancel */
static tree
cp_parser_omp_clause_if (cp_parser *parser, tree list, location_t location,
const char *p = IDENTIFIER_POINTER (id);
int n = 2;
- if (strcmp ("parallel", p) == 0)
+ if (strcmp ("cancel", p) == 0)
+ if_modifier = VOID_CST;
+ else if (strcmp ("parallel", p) == 0)
if_modifier = OMP_PARALLEL;
+ else if (strcmp ("simd", p) == 0)
+ if_modifier = OMP_SIMD;
else if (strcmp ("task", p) == 0)
if_modifier = OMP_TASK;
else if (strcmp ("taskloop", p) == 0)
}
}
- t = cp_parser_condition (parser);
+ t = cp_parser_assignment_expression (parser);
if (t == error_mark_node
|| !parens.require_close (parser))
const char *p = NULL;
switch (if_modifier)
{
+ case VOID_CST: p = "cancel"; break;
case OMP_PARALLEL: p = "parallel"; break;
+ case OMP_SIMD: p = "simd"; break;
case OMP_TASK: p = "task"; break;
case OMP_TASKLOOP: p = "taskloop"; break;
case OMP_TARGET_DATA: p = "target data"; break;
if (!parens.require_open (parser))
return list;
- t = cp_parser_expression (parser);
+ t = cp_parser_assignment_expression (parser);
if (t == error_mark_node
|| !parens.require_close (parser))
if (!parens.require_open (parser))
return list;
- t = cp_parser_expression (parser);
+ t = cp_parser_assignment_expression (parser);
if (t == error_mark_node
|| !parens.require_close (parser))
if (!parens.require_open (parser))
return list;
- t = cp_parser_expression (parser);
+ t = cp_parser_assignment_expression (parser);
if (t == error_mark_node
|| !parens.require_close (parser))
if (!parens.require_open (parser))
return list;
- t = cp_parser_expression (parser);
+ t = cp_parser_assignment_expression (parser);
if (t == error_mark_node
|| !parens.require_close (parser))
hint ( expression ) */
static tree
-cp_parser_omp_clause_hint (cp_parser *parser, tree list,
- location_t location)
+cp_parser_omp_clause_hint (cp_parser *parser, tree list, location_t location)
{
tree t, c;
if (!parens.require_open (parser))
return list;
- t = cp_parser_expression (parser);
+ t = cp_parser_assignment_expression (parser);
if (t == error_mark_node
|| !parens.require_close (parser))
}
/* OpenMP 4.5:
- defaultmap ( tofrom : scalar ) */
+ defaultmap ( tofrom : scalar )
+
+ OpenMP 5.0:
+ defaultmap ( implicit-behavior [ : variable-category ] ) */
static tree
cp_parser_omp_clause_defaultmap (cp_parser *parser, tree list,
{
tree c, id;
const char *p;
+ enum omp_clause_defaultmap_kind behavior = OMP_CLAUSE_DEFAULTMAP_DEFAULT;
+ enum omp_clause_defaultmap_kind category
+ = OMP_CLAUSE_DEFAULTMAP_CATEGORY_UNSPECIFIED;
matching_parens parens;
if (!parens.require_open (parser))
return list;
- if (!cp_lexer_next_token_is (parser->lexer, CPP_NAME))
+ if (cp_lexer_next_token_is_keyword (parser->lexer, RID_DEFAULT))
+ p = "default";
+ else if (!cp_lexer_next_token_is (parser->lexer, CPP_NAME))
{
- cp_parser_error (parser, "expected %<tofrom%>");
+ invalid_behavior:
+ cp_parser_error (parser, "expected %<alloc%>, %<to%>, %<from%>, "
+ "%<tofrom%>, %<firstprivate%>, %<none%> "
+ "or %<default%>");
goto out_err;
}
- id = cp_lexer_peek_token (parser->lexer)->u.value;
- p = IDENTIFIER_POINTER (id);
- if (strcmp (p, "tofrom") != 0)
+ else
{
- cp_parser_error (parser, "expected %<tofrom%>");
- goto out_err;
+ id = cp_lexer_peek_token (parser->lexer)->u.value;
+ p = IDENTIFIER_POINTER (id);
}
- cp_lexer_consume_token (parser->lexer);
- if (!cp_parser_require (parser, CPP_COLON, RT_COLON))
- goto out_err;
- if (!cp_lexer_next_token_is (parser->lexer, CPP_NAME))
+ switch (p[0])
{
- cp_parser_error (parser, "expected %<scalar%>");
- goto out_err;
+ case 'a':
+ if (strcmp ("alloc", p) == 0)
+ behavior = OMP_CLAUSE_DEFAULTMAP_ALLOC;
+ else
+ goto invalid_behavior;
+ break;
+
+ case 'd':
+ if (strcmp ("default", p) == 0)
+ behavior = OMP_CLAUSE_DEFAULTMAP_DEFAULT;
+ else
+ goto invalid_behavior;
+ break;
+
+ case 'f':
+ if (strcmp ("firstprivate", p) == 0)
+ behavior = OMP_CLAUSE_DEFAULTMAP_FIRSTPRIVATE;
+ else if (strcmp ("from", p) == 0)
+ behavior = OMP_CLAUSE_DEFAULTMAP_FROM;
+ else
+ goto invalid_behavior;
+ break;
+
+ case 'n':
+ if (strcmp ("none", p) == 0)
+ behavior = OMP_CLAUSE_DEFAULTMAP_NONE;
+ else
+ goto invalid_behavior;
+ break;
+
+ case 't':
+ if (strcmp ("tofrom", p) == 0)
+ behavior = OMP_CLAUSE_DEFAULTMAP_TOFROM;
+ else if (strcmp ("to", p) == 0)
+ behavior = OMP_CLAUSE_DEFAULTMAP_TO;
+ else
+ goto invalid_behavior;
+ break;
+
+ default:
+ goto invalid_behavior;
}
- id = cp_lexer_peek_token (parser->lexer)->u.value;
- p = IDENTIFIER_POINTER (id);
- if (strcmp (p, "scalar") != 0)
+ cp_lexer_consume_token (parser->lexer);
+
+ if (!cp_lexer_next_token_is (parser->lexer, CPP_CLOSE_PAREN))
{
- cp_parser_error (parser, "expected %<scalar%>");
- goto out_err;
+ if (!cp_parser_require (parser, CPP_COLON, RT_COLON))
+ goto out_err;
+
+ if (!cp_lexer_next_token_is (parser->lexer, CPP_NAME))
+ {
+ invalid_category:
+ cp_parser_error (parser, "expected %<scalar%>, %<aggregate%> or "
+ "%<pointer%>");
+ goto out_err;
+ }
+ id = cp_lexer_peek_token (parser->lexer)->u.value;
+ p = IDENTIFIER_POINTER (id);
+
+ switch (p[0])
+ {
+ case 'a':
+ if (strcmp ("aggregate", p) == 0)
+ category = OMP_CLAUSE_DEFAULTMAP_CATEGORY_AGGREGATE;
+ else
+ goto invalid_category;
+ break;
+
+ case 'p':
+ if (strcmp ("pointer", p) == 0)
+ category = OMP_CLAUSE_DEFAULTMAP_CATEGORY_POINTER;
+ else
+ goto invalid_category;
+ break;
+
+ case 's':
+ if (strcmp ("scalar", p) == 0)
+ category = OMP_CLAUSE_DEFAULTMAP_CATEGORY_SCALAR;
+ else
+ goto invalid_category;
+ break;
+
+ default:
+ goto invalid_category;
+ }
+
+ cp_lexer_consume_token (parser->lexer);
}
- cp_lexer_consume_token (parser->lexer);
if (!parens.require_close (parser))
goto out_err;
- check_no_duplicate_clause (list, OMP_CLAUSE_DEFAULTMAP, "defaultmap",
- location);
+ for (c = list; c ; c = OMP_CLAUSE_CHAIN (c))
+ if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_DEFAULTMAP
+ && (category == OMP_CLAUSE_DEFAULTMAP_CATEGORY_UNSPECIFIED
+ || OMP_CLAUSE_DEFAULTMAP_CATEGORY (c) == category
+ || (OMP_CLAUSE_DEFAULTMAP_CATEGORY (c)
+ == OMP_CLAUSE_DEFAULTMAP_CATEGORY_UNSPECIFIED)))
+ {
+ enum omp_clause_defaultmap_kind cat = category;
+ location_t loc = OMP_CLAUSE_LOCATION (c);
+ if (cat == OMP_CLAUSE_DEFAULTMAP_CATEGORY_UNSPECIFIED)
+ cat = OMP_CLAUSE_DEFAULTMAP_CATEGORY (c);
+ p = NULL;
+ switch (cat)
+ {
+ case OMP_CLAUSE_DEFAULTMAP_CATEGORY_UNSPECIFIED:
+ p = NULL;
+ break;
+ case OMP_CLAUSE_DEFAULTMAP_CATEGORY_AGGREGATE:
+ p = "aggregate";
+ break;
+ case OMP_CLAUSE_DEFAULTMAP_CATEGORY_POINTER:
+ p = "pointer";
+ break;
+ case OMP_CLAUSE_DEFAULTMAP_CATEGORY_SCALAR:
+ p = "scalar";
+ break;
+ default:
+ gcc_unreachable ();
+ }
+ if (p)
+ error_at (loc, "too many %<defaultmap%> clauses with %qs category",
+ p);
+ else
+ error_at (loc, "too many %<defaultmap%> clauses with unspecified "
+ "category");
+ break;
+ }
c = build_omp_clause (location, OMP_CLAUSE_DEFAULTMAP);
+ OMP_CLAUSE_DEFAULTMAP_SET_KIND (c, behavior, category);
OMP_CLAUSE_CHAIN (c) = list;
return c;
reduction-operator:
One of: + * - & ^ | && ||
- id-expression */
+ id-expression
+
+ OpenMP 5.0:
+ reduction ( reduction-modifier, reduction-operator : variable-list )
+ in_reduction ( reduction-operator : variable-list )
+ task_reduction ( reduction-operator : variable-list ) */
static tree
-cp_parser_omp_clause_reduction (cp_parser *parser, tree list)
+cp_parser_omp_clause_reduction (cp_parser *parser, enum omp_clause_code kind,
+ bool is_omp, tree list)
{
enum tree_code code = ERROR_MARK;
tree nlist, c, id = NULL_TREE;
+ bool task = false;
+ bool inscan = false;
if (!cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN))
return list;
+ if (kind == OMP_CLAUSE_REDUCTION && is_omp)
+ {
+ if (cp_lexer_next_token_is_keyword (parser->lexer, RID_DEFAULT)
+ && cp_lexer_nth_token_is (parser->lexer, 2, CPP_COMMA))
+ {
+ cp_lexer_consume_token (parser->lexer);
+ cp_lexer_consume_token (parser->lexer);
+ }
+ else if (cp_lexer_next_token_is (parser->lexer, CPP_NAME)
+ && cp_lexer_nth_token_is (parser->lexer, 2, CPP_COMMA))
+ {
+ tree id = cp_lexer_peek_token (parser->lexer)->u.value;
+ const char *p = IDENTIFIER_POINTER (id);
+ if (strcmp (p, "task") == 0)
+ task = true;
+ else if (strcmp (p, "inscan") == 0)
+ {
+ inscan = true;
+ sorry ("%<inscan%> modifier on %<reduction%> clause "
+ "not supported yet");
+ }
+ if (task || inscan)
+ {
+ cp_lexer_consume_token (parser->lexer);
+ cp_lexer_consume_token (parser->lexer);
+ }
+ }
+ }
+
switch (cp_lexer_peek_token (parser->lexer)->type)
{
case CPP_PLUS: code = PLUS_EXPR; break;
if (!cp_parser_require (parser, CPP_COLON, RT_COLON))
goto resync_fail;
- nlist = cp_parser_omp_var_list_no_open (parser, OMP_CLAUSE_REDUCTION, list,
+ nlist = cp_parser_omp_var_list_no_open (parser, kind, list,
NULL);
for (c = nlist; c != list; c = OMP_CLAUSE_CHAIN (c))
{
OMP_CLAUSE_REDUCTION_CODE (c) = code;
+ if (task)
+ OMP_CLAUSE_REDUCTION_TASK (c) = 1;
+ else if (inscan)
+ OMP_CLAUSE_REDUCTION_INSCAN (c) = 1;
OMP_CLAUSE_REDUCTION_PLACEHOLDER (c) = id;
}
if (!parens.require_open (parser))
return list;
- t = cp_parser_expression (parser);
+ t = cp_parser_assignment_expression (parser);
if (t == error_mark_node
|| !parens.require_close (parser))
if (!parens.require_open (parser))
return list;
- t = cp_parser_expression (parser);
+ t = cp_parser_assignment_expression (parser);
if (t == error_mark_node
|| !parens.require_close (parser))
return nlist;
}
+/* OpenMP 2.5:
+ lastprivate ( variable-list )
+
+ OpenMP 5.0:
+ lastprivate ( [ lastprivate-modifier : ] variable-list ) */
+
+static tree
+cp_parser_omp_clause_lastprivate (cp_parser *parser, tree list)
+{
+ bool conditional = false;
+
+ if (!cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN))
+ return list;
+
+ if (cp_lexer_next_token_is (parser->lexer, CPP_NAME)
+ && cp_lexer_nth_token_is (parser->lexer, 2, CPP_COLON))
+ {
+ tree id = cp_lexer_peek_token (parser->lexer)->u.value;
+ const char *p = IDENTIFIER_POINTER (id);
+
+ if (strcmp ("conditional", p) == 0)
+ {
+ conditional = true;
+ cp_lexer_consume_token (parser->lexer);
+ cp_lexer_consume_token (parser->lexer);
+ }
+ }
+
+ tree nlist = cp_parser_omp_var_list_no_open (parser, OMP_CLAUSE_LASTPRIVATE,
+ list, NULL);
+
+ if (conditional)
+ for (tree c = nlist; c != list; c = OMP_CLAUSE_CHAIN (c))
+ OMP_CLAUSE_LASTPRIVATE_CONDITIONAL (c) = 1;
+ return nlist;
+}
+
/* OpenMP 4.0:
linear ( variable-list )
linear ( variable-list : expression )
step = NULL_TREE;
}
if (!step)
- step = cp_parser_expression (parser);
+ step = cp_parser_assignment_expression (parser);
if (!parens.require_close (parser))
cp_parser_skip_to_closing_parenthesis (parser, /*recovering=*/true,
return list;
}
+/* OpenMP 5.0:
+ iterators ( iterators-definition )
+
+ iterators-definition:
+ iterator-specifier
+ iterator-specifier , iterators-definition
+
+ iterator-specifier:
+ identifier = range-specification
+ iterator-type identifier = range-specification
+
+ range-specification:
+ begin : end
+ begin : end : step */
+
+static tree
+cp_parser_omp_iterators (cp_parser *parser)
+{
+ tree ret = NULL_TREE, *last = &ret;
+ cp_lexer_consume_token (parser->lexer);
+
+ matching_parens parens;
+ if (!parens.require_open (parser))
+ return error_mark_node;
+
+ bool saved_colon_corrects_to_scope_p
+ = parser->colon_corrects_to_scope_p;
+ bool saved_colon_doesnt_start_class_def_p
+ = parser->colon_doesnt_start_class_def_p;
+
+ do
+ {
+ tree iter_type;
+ if (cp_lexer_next_token_is (parser->lexer, CPP_NAME)
+ && cp_lexer_nth_token_is (parser->lexer, 2, CPP_EQ))
+ iter_type = integer_type_node;
+ else
+ {
+ const char *saved_message
+ = parser->type_definition_forbidden_message;
+ parser->type_definition_forbidden_message
+ = G_("types may not be defined in iterator type");
+
+ iter_type = cp_parser_type_id (parser);
+
+ parser->type_definition_forbidden_message = saved_message;
+ }
+
+ location_t loc = cp_lexer_peek_token (parser->lexer)->location;
+ if (cp_lexer_next_token_is_not (parser->lexer, CPP_NAME))
+ {
+ cp_parser_error (parser, "expected identifier");
+ break;
+ }
+
+ tree id = cp_parser_identifier (parser);
+ if (id == error_mark_node)
+ break;
+
+ if (!cp_parser_require (parser, CPP_EQ, RT_EQ))
+ break;
+
+ parser->colon_corrects_to_scope_p = false;
+ parser->colon_doesnt_start_class_def_p = true;
+ tree begin = cp_parser_assignment_expression (parser);
+
+ if (!cp_parser_require (parser, CPP_COLON, RT_COLON))
+ break;
+
+ tree end = cp_parser_assignment_expression (parser);
+
+ tree step = integer_one_node;
+ if (cp_lexer_next_token_is (parser->lexer, CPP_COLON))
+ {
+ cp_lexer_consume_token (parser->lexer);
+ step = cp_parser_assignment_expression (parser);
+ }
+
+ tree iter_var = build_decl (loc, VAR_DECL, id, iter_type);
+ DECL_ARTIFICIAL (iter_var) = 1;
+ DECL_CONTEXT (iter_var) = current_function_decl;
+ pushdecl (iter_var);
+
+ *last = make_tree_vec (6);
+ TREE_VEC_ELT (*last, 0) = iter_var;
+ TREE_VEC_ELT (*last, 1) = begin;
+ TREE_VEC_ELT (*last, 2) = end;
+ TREE_VEC_ELT (*last, 3) = step;
+ last = &TREE_CHAIN (*last);
+
+ if (cp_lexer_next_token_is (parser->lexer, CPP_COMMA))
+ {
+ cp_lexer_consume_token (parser->lexer);
+ continue;
+ }
+ break;
+ }
+ while (1);
+
+ parser->colon_corrects_to_scope_p = saved_colon_corrects_to_scope_p;
+ parser->colon_doesnt_start_class_def_p
+ = saved_colon_doesnt_start_class_def_p;
+
+ if (!parens.require_close (parser))
+ cp_parser_skip_to_closing_parenthesis (parser,
+ /*recovering=*/true,
+ /*or_comma=*/false,
+ /*consume_paren=*/true);
+
+ return ret ? ret : error_mark_node;
+}
+
/* OpenMP 4.0:
depend ( depend-kind : variable-list )
OpenMP 4.5:
depend ( source )
- depend ( sink : vec ) */
+ depend ( sink : vec )
+
+ OpenMP 5.0:
+ depend ( depend-modifier , depend-kind: variable-list )
+
+ depend-kind:
+ in | out | inout | mutexinoutset | depobj
+
+ depend-modifier:
+ iterator ( iterators-definition ) */
static tree
cp_parser_omp_clause_depend (cp_parser *parser, tree list, location_t loc)
{
- tree nlist, c;
- enum omp_clause_depend_kind kind = OMP_CLAUSE_DEPEND_INOUT;
+ tree nlist, c, iterators = NULL_TREE;
+ enum omp_clause_depend_kind kind = OMP_CLAUSE_DEPEND_LAST;
matching_parens parens;
if (!parens.require_open (parser))
return list;
- if (cp_lexer_next_token_is (parser->lexer, CPP_NAME))
+ do
{
+ if (cp_lexer_next_token_is_not (parser->lexer, CPP_NAME))
+ goto invalid_kind;
+
tree id = cp_lexer_peek_token (parser->lexer)->u.value;
const char *p = IDENTIFIER_POINTER (id);
+ if (strcmp ("iterator", p) == 0 && iterators == NULL_TREE)
+ {
+ begin_scope (sk_omp, NULL);
+ iterators = cp_parser_omp_iterators (parser);
+ cp_parser_require (parser, CPP_COMMA, RT_COMMA);
+ continue;
+ }
if (strcmp ("in", p) == 0)
kind = OMP_CLAUSE_DEPEND_IN;
else if (strcmp ("inout", p) == 0)
kind = OMP_CLAUSE_DEPEND_INOUT;
+ else if (strcmp ("mutexinoutset", p) == 0)
+ kind = OMP_CLAUSE_DEPEND_MUTEXINOUTSET;
else if (strcmp ("out", p) == 0)
kind = OMP_CLAUSE_DEPEND_OUT;
- else if (strcmp ("source", p) == 0)
- kind = OMP_CLAUSE_DEPEND_SOURCE;
+ else if (strcmp ("depobj", p) == 0)
+ kind = OMP_CLAUSE_DEPEND_DEPOBJ;
else if (strcmp ("sink", p) == 0)
kind = OMP_CLAUSE_DEPEND_SINK;
+ else if (strcmp ("source", p) == 0)
+ kind = OMP_CLAUSE_DEPEND_SOURCE;
else
goto invalid_kind;
+ break;
}
- else
- goto invalid_kind;
+ while (1);
cp_lexer_consume_token (parser->lexer);
+ if (iterators
+ && (kind == OMP_CLAUSE_DEPEND_SOURCE || kind == OMP_CLAUSE_DEPEND_SINK))
+ {
+ poplevel (0, 1, 0);
+ error_at (loc, "%<iterator%> modifier incompatible with %qs",
+ kind == OMP_CLAUSE_DEPEND_SOURCE ? "source" : "sink");
+ iterators = NULL_TREE;
+ }
+
if (kind == OMP_CLAUSE_DEPEND_SOURCE)
{
c = build_omp_clause (loc, OMP_CLAUSE_DEPEND);
nlist = cp_parser_omp_var_list_no_open (parser, OMP_CLAUSE_DEPEND,
list, NULL);
+ if (iterators)
+ {
+ tree block = poplevel (1, 1, 0);
+ if (iterators == error_mark_node)
+ iterators = NULL_TREE;
+ else
+ TREE_VEC_ELT (iterators, 5) = block;
+ }
+
for (c = nlist; c != list; c = OMP_CLAUSE_CHAIN (c))
- OMP_CLAUSE_DEPEND_KIND (c) = kind;
+ {
+ OMP_CLAUSE_DEPEND_KIND (c) = kind;
+ if (iterators)
+ OMP_CLAUSE_DECL (c)
+ = build_tree_list (iterators, OMP_CLAUSE_DECL (c));
+ }
}
return nlist;
invalid_kind:
cp_parser_error (parser, "invalid depend kind");
resync_fail:
+ if (iterators)
+ poplevel (0, 1, 0);
cp_parser_skip_to_closing_parenthesis (parser, /*recovering=*/true,
/*or_comma=*/false,
/*consume_paren=*/true);
if (!parens.require_open (parser))
return list;
- t = cp_parser_expression (parser);
+ t = cp_parser_assignment_expression (parser);
if (t == error_mark_node
|| !parens.require_close (parser))
c_name = "async";
break;
case PRAGMA_OACC_CLAUSE_AUTO:
- clauses = cp_parser_oacc_simple_clause (parser, OMP_CLAUSE_AUTO,
- clauses, here);
+ clauses = cp_parser_oacc_simple_clause (here, OMP_CLAUSE_AUTO,
+ clauses);
c_name = "auto";
break;
case PRAGMA_OACC_CLAUSE_COLLAPSE:
clauses = cp_parser_oacc_data_clause (parser, c_kind, clauses);
c_name = "device_resident";
break;
+ case PRAGMA_OACC_CLAUSE_FINALIZE:
+ clauses = cp_parser_oacc_simple_clause (here, OMP_CLAUSE_FINALIZE,
+ clauses);
+ c_name = "finalize";
+ break;
case PRAGMA_OACC_CLAUSE_FIRSTPRIVATE:
clauses = cp_parser_omp_var_list (parser, OMP_CLAUSE_FIRSTPRIVATE,
clauses);
break;
case PRAGMA_OACC_CLAUSE_GANG:
c_name = "gang";
- clauses = cp_parser_oacc_shape_clause (parser, OMP_CLAUSE_GANG,
+ clauses = cp_parser_oacc_shape_clause (parser, here, OMP_CLAUSE_GANG,
c_name, clauses);
break;
case PRAGMA_OACC_CLAUSE_HOST:
clauses = cp_parser_omp_clause_if (parser, clauses, here, false);
c_name = "if";
break;
+ case PRAGMA_OACC_CLAUSE_IF_PRESENT:
+ clauses = cp_parser_oacc_simple_clause (here, OMP_CLAUSE_IF_PRESENT,
+ clauses);
+ c_name = "if_present";
+ break;
case PRAGMA_OACC_CLAUSE_INDEPENDENT:
- clauses = cp_parser_oacc_simple_clause (parser,
- OMP_CLAUSE_INDEPENDENT,
- clauses, here);
+ clauses = cp_parser_oacc_simple_clause (here, OMP_CLAUSE_INDEPENDENT,
+ clauses);
c_name = "independent";
break;
case PRAGMA_OACC_CLAUSE_LINK:
clauses = cp_parser_oacc_data_clause (parser, c_kind, clauses);
c_name = "present";
break;
- case PRAGMA_OACC_CLAUSE_PRESENT_OR_COPY:
- clauses = cp_parser_oacc_data_clause (parser, c_kind, clauses);
- c_name = "present_or_copy";
- break;
- case PRAGMA_OACC_CLAUSE_PRESENT_OR_COPYIN:
- clauses = cp_parser_oacc_data_clause (parser, c_kind, clauses);
- c_name = "present_or_copyin";
- break;
- case PRAGMA_OACC_CLAUSE_PRESENT_OR_COPYOUT:
- clauses = cp_parser_oacc_data_clause (parser, c_kind, clauses);
- c_name = "present_or_copyout";
- break;
- case PRAGMA_OACC_CLAUSE_PRESENT_OR_CREATE:
- clauses = cp_parser_oacc_data_clause (parser, c_kind, clauses);
- c_name = "present_or_create";
- break;
case PRAGMA_OACC_CLAUSE_PRIVATE:
clauses = cp_parser_omp_var_list (parser, OMP_CLAUSE_PRIVATE,
clauses);
c_name = "private";
break;
case PRAGMA_OACC_CLAUSE_REDUCTION:
- clauses = cp_parser_omp_clause_reduction (parser, clauses);
+ clauses
+ = cp_parser_omp_clause_reduction (parser, OMP_CLAUSE_REDUCTION,
+ false, clauses);
c_name = "reduction";
break;
- case PRAGMA_OACC_CLAUSE_SELF:
- clauses = cp_parser_oacc_data_clause (parser, c_kind, clauses);
- c_name = "self";
- break;
case PRAGMA_OACC_CLAUSE_SEQ:
- clauses = cp_parser_oacc_simple_clause (parser, OMP_CLAUSE_SEQ,
- clauses, here);
+ clauses = cp_parser_oacc_simple_clause (here, OMP_CLAUSE_SEQ,
+ clauses);
c_name = "seq";
break;
case PRAGMA_OACC_CLAUSE_TILE:
break;
case PRAGMA_OACC_CLAUSE_VECTOR:
c_name = "vector";
- clauses = cp_parser_oacc_shape_clause (parser, OMP_CLAUSE_VECTOR,
+ clauses = cp_parser_oacc_shape_clause (parser, here,
+ OMP_CLAUSE_VECTOR,
c_name, clauses);
break;
case PRAGMA_OACC_CLAUSE_VECTOR_LENGTH:
break;
case PRAGMA_OACC_CLAUSE_WORKER:
c_name = "worker";
- clauses = cp_parser_oacc_shape_clause (parser, OMP_CLAUSE_WORKER,
+ clauses = cp_parser_oacc_shape_clause (parser, here,
+ OMP_CLAUSE_WORKER,
c_name, clauses);
break;
default:
bool first = true;
cp_token *token = NULL;
+ /* Don't create location wrapper nodes within OpenMP clauses. */
+ auto_suppress_location_wrappers sentinel;
+
while (cp_lexer_next_token_is_not (parser->lexer, CPP_PRAGMA_EOL))
{
pragma_omp_clause c_kind;
true);
c_name = "if";
break;
+ case PRAGMA_OMP_CLAUSE_IN_REDUCTION:
+ clauses
+ = cp_parser_omp_clause_reduction (parser, OMP_CLAUSE_IN_REDUCTION,
+ true, clauses);
+ c_name = "in_reduction";
+ break;
case PRAGMA_OMP_CLAUSE_LASTPRIVATE:
- clauses = cp_parser_omp_var_list (parser, OMP_CLAUSE_LASTPRIVATE,
- clauses);
+ clauses = cp_parser_omp_clause_lastprivate (parser, clauses);
c_name = "lastprivate";
break;
case PRAGMA_OMP_CLAUSE_MERGEABLE:
c_name = "private";
break;
case PRAGMA_OMP_CLAUSE_REDUCTION:
- clauses = cp_parser_omp_clause_reduction (parser, clauses);
+ clauses
+ = cp_parser_omp_clause_reduction (parser, OMP_CLAUSE_REDUCTION,
+ true, clauses);
c_name = "reduction";
break;
case PRAGMA_OMP_CLAUSE_SCHEDULE:
clauses);
c_name = "shared";
break;
+ case PRAGMA_OMP_CLAUSE_TASK_REDUCTION:
+ clauses
+ = cp_parser_omp_clause_reduction (parser,
+ OMP_CLAUSE_TASK_REDUCTION,
+ true, clauses);
+ c_name = "task_reduction";
+ break;
case PRAGMA_OMP_CLAUSE_UNTIED:
clauses = cp_parser_omp_clause_untied (parser, clauses,
token->location);
clauses, token->location);
c_name = "inbranch";
break;
+ case PRAGMA_OMP_CLAUSE_NONTEMPORAL:
+ clauses = cp_parser_omp_var_list (parser, OMP_CLAUSE_NONTEMPORAL,
+ clauses);
+ c_name = "nontemporal";
+ break;
case PRAGMA_OMP_CLAUSE_NOTINBRANCH:
clauses = cp_parser_omp_clause_branch (parser,
OMP_CLAUSE_NOTINBRANCH,
{
tree lhs = NULL_TREE, rhs = NULL_TREE, v = NULL_TREE, lhs1 = NULL_TREE;
tree rhs1 = NULL_TREE, orig_lhs;
- enum tree_code code = OMP_ATOMIC, opcode = NOP_EXPR;
+ location_t loc = pragma_tok->location;
+ enum tree_code code = ERROR_MARK, opcode = NOP_EXPR;
+ enum omp_memory_order memory_order = OMP_MEMORY_ORDER_UNSPECIFIED;
bool structured_block = false;
- bool seq_cst = false;
-
- 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, "seq_cst"))
- {
- seq_cst = true;
- cp_lexer_consume_token (parser->lexer);
- if (cp_lexer_next_token_is (parser->lexer, CPP_COMMA)
- && cp_lexer_peek_nth_token (parser->lexer, 2)->type == CPP_NAME)
- 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);
+ bool first = true;
+ tree clauses = NULL_TREE;
- if (!strcmp (p, "read"))
- code = OMP_ATOMIC_READ;
- else if (!strcmp (p, "write"))
- code = NOP_EXPR;
- else if (!strcmp (p, "update"))
- code = OMP_ATOMIC;
- else if (!strcmp (p, "capture"))
- code = OMP_ATOMIC_CAPTURE_NEW;
- else
- p = NULL;
- if (p)
- cp_lexer_consume_token (parser->lexer);
- }
- if (!seq_cst)
+ while (cp_lexer_next_token_is_not (parser->lexer, CPP_PRAGMA_EOL))
{
- if (cp_lexer_next_token_is (parser->lexer, CPP_COMMA)
- && cp_lexer_peek_nth_token (parser->lexer, 2)->type == CPP_NAME)
+ if (!first && cp_lexer_next_token_is (parser->lexer, CPP_COMMA))
cp_lexer_consume_token (parser->lexer);
+ first = false;
+
if (cp_lexer_next_token_is (parser->lexer, CPP_NAME))
{
tree id = cp_lexer_peek_token (parser->lexer)->u.value;
+ location_t cloc = cp_lexer_peek_token (parser->lexer)->location;
const char *p = IDENTIFIER_POINTER (id);
-
- if (!strcmp (p, "seq_cst"))
+ enum tree_code new_code = ERROR_MARK;
+ enum omp_memory_order new_memory_order
+ = OMP_MEMORY_ORDER_UNSPECIFIED;
+
+ if (!strcmp (p, "read"))
+ new_code = OMP_ATOMIC_READ;
+ else if (!strcmp (p, "write"))
+ new_code = NOP_EXPR;
+ else if (!strcmp (p, "update"))
+ new_code = OMP_ATOMIC;
+ else if (!strcmp (p, "capture"))
+ new_code = OMP_ATOMIC_CAPTURE_NEW;
+ else if (!strcmp (p, "seq_cst"))
+ new_memory_order = OMP_MEMORY_ORDER_SEQ_CST;
+ else if (!strcmp (p, "acq_rel"))
+ new_memory_order = OMP_MEMORY_ORDER_ACQ_REL;
+ else if (!strcmp (p, "release"))
+ new_memory_order = OMP_MEMORY_ORDER_RELEASE;
+ else if (!strcmp (p, "acquire"))
+ new_memory_order = OMP_MEMORY_ORDER_ACQUIRE;
+ else if (!strcmp (p, "relaxed"))
+ new_memory_order = OMP_MEMORY_ORDER_RELAXED;
+ else if (!strcmp (p, "hint"))
+ {
+ cp_lexer_consume_token (parser->lexer);
+ clauses = cp_parser_omp_clause_hint (parser, clauses, cloc);
+ continue;
+ }
+ else
+ {
+ p = NULL;
+ error_at (cloc, "expected %<read%>, %<write%>, %<update%>, "
+ "%<capture%>, %<seq_cst%>, %<acq_rel%>, "
+ "%<release%>, %<relaxed%> or %<hint%> clause");
+ }
+ if (p)
{
- seq_cst = true;
+ if (new_code != ERROR_MARK)
+ {
+ if (code != ERROR_MARK)
+ error_at (cloc, "too many atomic clauses");
+ else
+ code = new_code;
+ }
+ else if (new_memory_order != OMP_MEMORY_ORDER_UNSPECIFIED)
+ {
+ if (memory_order != OMP_MEMORY_ORDER_UNSPECIFIED)
+ error_at (cloc, "too many memory order clauses");
+ else
+ memory_order = new_memory_order;
+ }
cp_lexer_consume_token (parser->lexer);
+ continue;
}
}
+ break;
}
cp_parser_require_pragma_eol (parser, pragma_tok);
+ if (code == ERROR_MARK)
+ code = OMP_ATOMIC;
+ if (memory_order == OMP_MEMORY_ORDER_UNSPECIFIED)
+ {
+ omp_requires_mask
+ = (enum omp_requires) (omp_requires_mask
+ | OMP_REQUIRES_ATOMIC_DEFAULT_MEM_ORDER_USED);
+ switch ((enum omp_memory_order)
+ (omp_requires_mask & OMP_REQUIRES_ATOMIC_DEFAULT_MEM_ORDER))
+ {
+ case OMP_MEMORY_ORDER_UNSPECIFIED:
+ case OMP_MEMORY_ORDER_RELAXED:
+ memory_order = OMP_MEMORY_ORDER_RELAXED;
+ break;
+ case OMP_MEMORY_ORDER_SEQ_CST:
+ memory_order = OMP_MEMORY_ORDER_SEQ_CST;
+ break;
+ case OMP_MEMORY_ORDER_ACQ_REL:
+ switch (code)
+ {
+ case OMP_ATOMIC_READ:
+ memory_order = OMP_MEMORY_ORDER_ACQUIRE;
+ break;
+ case NOP_EXPR: /* atomic write */
+ case OMP_ATOMIC:
+ memory_order = OMP_MEMORY_ORDER_RELEASE;
+ break;
+ default:
+ memory_order = OMP_MEMORY_ORDER_ACQ_REL;
+ break;
+ }
+ break;
+ default:
+ gcc_unreachable ();
+ }
+ }
+ else
+ switch (code)
+ {
+ case OMP_ATOMIC_READ:
+ if (memory_order == OMP_MEMORY_ORDER_ACQ_REL
+ || memory_order == OMP_MEMORY_ORDER_RELEASE)
+ {
+ error_at (loc, "%<#pragma omp atomic read%> incompatible with "
+ "%<acq_rel%> or %<release%> clauses");
+ memory_order = OMP_MEMORY_ORDER_SEQ_CST;
+ }
+ break;
+ case NOP_EXPR: /* atomic write */
+ if (memory_order == OMP_MEMORY_ORDER_ACQ_REL
+ || memory_order == OMP_MEMORY_ORDER_ACQUIRE)
+ {
+ error_at (loc, "%<#pragma omp atomic write%> incompatible with "
+ "%<acq_rel%> or %<acquire%> clauses");
+ memory_order = OMP_MEMORY_ORDER_SEQ_CST;
+ }
+ break;
+ case OMP_ATOMIC:
+ if (memory_order == OMP_MEMORY_ORDER_ACQ_REL
+ || memory_order == OMP_MEMORY_ORDER_ACQUIRE)
+ {
+ error_at (loc, "%<#pragma omp atomic update%> incompatible with "
+ "%<acq_rel%> or %<acquire%> clauses");
+ memory_order = OMP_MEMORY_ORDER_SEQ_CST;
+ }
+ break;
+ default:
+ break;
+ }
+
switch (code)
{
case OMP_ATOMIC_READ:
cp_parser_require (parser, CPP_CLOSE_BRACE, RT_CLOSE_BRACE);
}
done:
- finish_omp_atomic (code, opcode, lhs, rhs, v, lhs1, rhs1, seq_cst);
+ clauses = finish_omp_clauses (clauses, C_ORT_OMP);
+ finish_omp_atomic (pragma_tok->location, code, opcode, lhs, rhs, v, lhs1,
+ rhs1, clauses, memory_order);
if (!structured_block)
cp_parser_consume_semicolon_at_end_of_statement (parser);
return;
if (name == error_mark_node)
name = NULL;
+ if (cp_lexer_next_token_is (parser->lexer, CPP_COMMA)
+ && cp_lexer_nth_token_is (parser->lexer, 2, CPP_NAME))
+ cp_lexer_consume_token (parser->lexer);
+
clauses = cp_parser_omp_all_clauses (parser,
OMP_CRITICAL_CLAUSE_MASK,
"#pragma omp critical", pragma_tok);
return c_finish_omp_critical (input_location, stmt, name, clauses);
}
+/* OpenMP 5.0:
+ # pragma omp depobj ( depobj ) depobj-clause new-line
+
+ depobj-clause:
+ depend (dependence-type : locator)
+ destroy
+ update (dependence-type)
+
+ dependence-type:
+ in
+ out
+ inout
+ mutexinout */
+
+static void
+cp_parser_omp_depobj (cp_parser *parser, cp_token *pragma_tok)
+{
+ location_t loc = pragma_tok->location;
+ matching_parens parens;
+ if (!parens.require_open (parser))
+ {
+ cp_parser_skip_to_pragma_eol (parser, pragma_tok);
+ return;
+ }
+
+ tree depobj = cp_parser_assignment_expression (parser);
+
+ if (!parens.require_close (parser))
+ cp_parser_skip_to_closing_parenthesis (parser, /*recovering=*/true,
+ /*or_comma=*/false,
+ /*consume_paren=*/true);
+
+ tree clause = NULL_TREE;
+ enum omp_clause_depend_kind kind = OMP_CLAUSE_DEPEND_SOURCE;
+ location_t c_loc = cp_lexer_peek_token (parser->lexer)->location;
+ 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);
+
+ cp_lexer_consume_token (parser->lexer);
+ if (!strcmp ("depend", p))
+ {
+ clause = cp_parser_omp_clause_depend (parser, NULL_TREE, c_loc);
+ if (clause)
+ clause = finish_omp_clauses (clause, C_ORT_OMP);
+ if (!clause)
+ clause = error_mark_node;
+ }
+ else if (!strcmp ("destroy", p))
+ kind = OMP_CLAUSE_DEPEND_LAST;
+ else if (!strcmp ("update", p))
+ {
+ matching_parens c_parens;
+ if (c_parens.require_open (parser))
+ {
+ location_t c2_loc
+ = cp_lexer_peek_token (parser->lexer)->location;
+ if (cp_lexer_next_token_is (parser->lexer, CPP_NAME))
+ {
+ tree id2 = cp_lexer_peek_token (parser->lexer)->u.value;
+ const char *p2 = IDENTIFIER_POINTER (id2);
+
+ cp_lexer_consume_token (parser->lexer);
+ if (!strcmp ("in", p2))
+ kind = OMP_CLAUSE_DEPEND_IN;
+ else if (!strcmp ("out", p2))
+ kind = OMP_CLAUSE_DEPEND_OUT;
+ else if (!strcmp ("inout", p2))
+ kind = OMP_CLAUSE_DEPEND_INOUT;
+ else if (!strcmp ("mutexinoutset", p2))
+ kind = OMP_CLAUSE_DEPEND_MUTEXINOUTSET;
+ }
+ if (kind == OMP_CLAUSE_DEPEND_SOURCE)
+ {
+ clause = error_mark_node;
+ error_at (c2_loc, "expected %<in%>, %<out%>, %<inout%> or "
+ "%<mutexinoutset%>");
+ }
+ if (!c_parens.require_close (parser))
+ cp_parser_skip_to_closing_parenthesis (parser,
+ /*recovering=*/true,
+ /*or_comma=*/false,
+ /*consume_paren=*/true);
+ }
+ else
+ clause = error_mark_node;
+ }
+ }
+ if (!clause && kind == OMP_CLAUSE_DEPEND_SOURCE)
+ {
+ clause = error_mark_node;
+ error_at (c_loc, "expected %<depend%>, %<destroy%> or %<update%> clause");
+ }
+ cp_parser_require_pragma_eol (parser, pragma_tok);
+
+ finish_omp_depobj (loc, depobj, kind, clause);
+}
+
+
/* OpenMP 2.5:
# pragma omp flush flush-vars[opt] new-line
flush-vars:
- ( variable-list ) */
+ ( variable-list )
+
+ OpenMP 5.0:
+ # pragma omp flush memory-order-clause new-line */
static void
cp_parser_omp_flush (cp_parser *parser, cp_token *pragma_tok)
{
+ enum memmodel mo = MEMMODEL_LAST;
+ 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, "acq_rel"))
+ mo = MEMMODEL_ACQ_REL;
+ else if (!strcmp (p, "release"))
+ mo = MEMMODEL_RELEASE;
+ else if (!strcmp (p, "acquire"))
+ mo = MEMMODEL_ACQUIRE;
+ else
+ error_at (cp_lexer_peek_token (parser->lexer)->location,
+ "expected %<acq_rel%>, %<release%> or %<acquire%>");
+ cp_lexer_consume_token (parser->lexer);
+ }
if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_PAREN))
- (void) cp_parser_omp_var_list (parser, OMP_CLAUSE_ERROR, NULL);
+ {
+ if (mo != MEMMODEL_LAST)
+ error_at (cp_lexer_peek_token (parser->lexer)->location,
+ "%<flush%> list specified together with memory order "
+ "clause");
+ (void) cp_parser_omp_var_list (parser, OMP_CLAUSE_ERROR, NULL);
+ }
cp_parser_require_pragma_eol (parser, pragma_tok);
- finish_omp_flush ();
+ finish_omp_flush (mo);
}
/* Helper function, to parse omp for increment expression. */
static tree
-cp_parser_omp_for_cond (cp_parser *parser, tree decl)
+cp_parser_omp_for_cond (cp_parser *parser, tree decl, enum tree_code code)
{
tree cond = cp_parser_binary_expression (parser, false, true,
PREC_NOT_OPERATOR, NULL);
case LE_EXPR:
break;
case NE_EXPR:
- /* Fall through: OpenMP disallows NE_EXPR. */
+ if (code != OACC_LOOP)
+ break;
gcc_fallthrough ();
default:
return error_mark_node;
|| CLASS_TYPE_P (TREE_TYPE (decl))))
return cond;
- return build_x_binary_op (EXPR_LOC_OR_LOC (cond, input_location),
+ return build_x_binary_op (cp_expr_loc_or_loc (cond, input_location),
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,
+ vec<tree, va_gc> *&for_block,
tree &init,
tree &orig_init,
tree &decl,
cp_parser_condition, from whence the bulk of this is copied. */
cp_parser_parse_tentatively (parser);
- cp_parser_type_specifier_seq (parser, /*is_declaration=*/true,
+ cp_parser_type_specifier_seq (parser, CP_PARSER_FLAGS_NONE,
+ /*is_declaration=*/true,
/*is_trailing_return=*/false,
&type_specifiers);
if (cp_parser_parse_definitely (parser))
declarator = cp_parser_declarator (parser,
CP_PARSER_DECLARATOR_NAMED,
+ CP_PARSER_FLAGS_NONE,
/*ctor_dtor_or_conv_p=*/NULL,
/*parenthesized_p=*/NULL,
/*member_p=*/false,
- /*friend_p=*/false);
+ /*friend_p=*/false,
+ /*static_p=*/false);
attributes = cp_parser_attributes_opt (parser);
asm_specification = cp_parser_asm_specification_opt (parser);
return add_private_clause;
}
+/* Helper for cp_parser_omp_for_loop, handle one range-for loop. */
+
+void
+cp_convert_omp_range_for (tree &this_pre_body, vec<tree, va_gc> *for_block,
+ tree &decl, tree &orig_decl, tree &init,
+ tree &orig_init, tree &cond, tree &incr)
+{
+ tree begin, end, range_temp_decl = NULL_TREE;
+ tree iter_type, begin_expr, end_expr;
+
+ if (processing_template_decl)
+ {
+ if (check_for_bare_parameter_packs (init))
+ init = error_mark_node;
+ if (!type_dependent_expression_p (init)
+ /* do_auto_deduction doesn't mess with template init-lists. */
+ && !BRACE_ENCLOSED_INITIALIZER_P (init))
+ {
+ tree d = decl;
+ if (decl != error_mark_node && DECL_HAS_VALUE_EXPR_P (decl))
+ {
+ tree v = DECL_VALUE_EXPR (decl);
+ if (TREE_CODE (v) == ARRAY_REF
+ && VAR_P (TREE_OPERAND (v, 0))
+ && DECL_DECOMPOSITION_P (TREE_OPERAND (v, 0)))
+ d = TREE_OPERAND (v, 0);
+ }
+ do_range_for_auto_deduction (d, init);
+ }
+ cond = global_namespace;
+ incr = NULL_TREE;
+ orig_init = init;
+ if (this_pre_body)
+ this_pre_body = pop_stmt_list (this_pre_body);
+ return;
+ }
+
+ init = mark_lvalue_use (init);
+
+ if (decl == error_mark_node || init == error_mark_node)
+ /* If an error happened previously do nothing or else a lot of
+ unhelpful errors would be issued. */
+ begin_expr = end_expr = iter_type = error_mark_node;
+ else
+ {
+ tree range_temp;
+
+ if (VAR_P (init)
+ && array_of_runtime_bound_p (TREE_TYPE (init)))
+ /* Can't bind a reference to an array of runtime bound. */
+ range_temp = init;
+ else
+ {
+ range_temp = build_range_temp (init);
+ DECL_NAME (range_temp) = NULL_TREE;
+ pushdecl (range_temp);
+ cp_finish_decl (range_temp, init,
+ /*is_constant_init*/false, NULL_TREE,
+ LOOKUP_ONLYCONVERTING);
+ range_temp_decl = range_temp;
+ range_temp = convert_from_reference (range_temp);
+ }
+ iter_type = cp_parser_perform_range_for_lookup (range_temp,
+ &begin_expr, &end_expr);
+ }
+
+ tree end_iter_type = iter_type;
+ if (cxx_dialect >= cxx17)
+ end_iter_type = cv_unqualified (TREE_TYPE (end_expr));
+ end = build_decl (input_location, VAR_DECL, NULL_TREE, end_iter_type);
+ TREE_USED (end) = 1;
+ DECL_ARTIFICIAL (end) = 1;
+ pushdecl (end);
+ cp_finish_decl (end, end_expr,
+ /*is_constant_init*/false, NULL_TREE,
+ LOOKUP_ONLYCONVERTING);
+
+ /* The new for initialization statement. */
+ begin = build_decl (input_location, VAR_DECL, NULL_TREE, iter_type);
+ TREE_USED (begin) = 1;
+ DECL_ARTIFICIAL (begin) = 1;
+ pushdecl (begin);
+ orig_init = init;
+ if (CLASS_TYPE_P (iter_type))
+ init = NULL_TREE;
+ else
+ {
+ init = begin_expr;
+ begin_expr = NULL_TREE;
+ }
+ cp_finish_decl (begin, begin_expr,
+ /*is_constant_init*/false, NULL_TREE,
+ LOOKUP_ONLYCONVERTING);
+
+ /* The new for condition. */
+ if (CLASS_TYPE_P (iter_type))
+ cond = build2 (NE_EXPR, boolean_type_node, begin, end);
+ else
+ cond = build_x_binary_op (input_location, NE_EXPR,
+ begin, ERROR_MARK,
+ end, ERROR_MARK,
+ NULL, tf_warning_or_error);
+
+ /* The new increment expression. */
+ if (CLASS_TYPE_P (iter_type))
+ incr = build2 (PREINCREMENT_EXPR, iter_type, begin, NULL_TREE);
+ else
+ incr = finish_unary_op_expr (input_location,
+ PREINCREMENT_EXPR, begin,
+ tf_warning_or_error);
+
+ orig_decl = decl;
+ decl = begin;
+ if (for_block)
+ {
+ vec_safe_push (for_block, this_pre_body);
+ this_pre_body = NULL_TREE;
+ }
+
+ tree decomp_first_name = NULL_TREE;
+ unsigned decomp_cnt = 0;
+ if (orig_decl != error_mark_node && DECL_HAS_VALUE_EXPR_P (orig_decl))
+ {
+ tree v = DECL_VALUE_EXPR (orig_decl);
+ if (TREE_CODE (v) == ARRAY_REF
+ && VAR_P (TREE_OPERAND (v, 0))
+ && DECL_DECOMPOSITION_P (TREE_OPERAND (v, 0)))
+ {
+ tree d = orig_decl;
+ orig_decl = TREE_OPERAND (v, 0);
+ decomp_cnt = tree_to_uhwi (TREE_OPERAND (v, 1)) + 1;
+ decomp_first_name = d;
+ }
+ }
+
+ tree auto_node = type_uses_auto (TREE_TYPE (orig_decl));
+ if (auto_node)
+ {
+ tree t = build_x_indirect_ref (input_location, begin, RO_UNARY_STAR,
+ tf_none);
+ if (!error_operand_p (t))
+ TREE_TYPE (orig_decl) = do_auto_deduction (TREE_TYPE (orig_decl),
+ t, auto_node);
+ }
+
+ tree v = make_tree_vec (decomp_cnt + 3);
+ TREE_VEC_ELT (v, 0) = range_temp_decl;
+ TREE_VEC_ELT (v, 1) = end;
+ TREE_VEC_ELT (v, 2) = orig_decl;
+ for (unsigned i = 0; i < decomp_cnt; i++)
+ {
+ TREE_VEC_ELT (v, i + 3) = decomp_first_name;
+ decomp_first_name = DECL_CHAIN (decomp_first_name);
+ }
+ orig_decl = tree_cons (NULL_TREE, NULL_TREE, v);
+}
+
+/* Helper for cp_parser_omp_for_loop, finalize part of range for
+ inside of the collapsed body. */
+
+void
+cp_finish_omp_range_for (tree orig, tree begin)
+{
+ gcc_assert (TREE_CODE (orig) == TREE_LIST
+ && TREE_CODE (TREE_CHAIN (orig)) == TREE_VEC);
+ tree decl = TREE_VEC_ELT (TREE_CHAIN (orig), 2);
+ tree decomp_first_name = NULL_TREE;
+ unsigned int decomp_cnt = 0;
+
+ if (VAR_P (decl) && DECL_DECOMPOSITION_P (decl))
+ {
+ decomp_first_name = TREE_VEC_ELT (TREE_CHAIN (orig), 3);
+ decomp_cnt = TREE_VEC_LENGTH (TREE_CHAIN (orig)) - 3;
+ cp_maybe_mangle_decomp (decl, decomp_first_name, decomp_cnt);
+ }
+
+ /* The declaration is initialized with *__begin inside the loop body. */
+ cp_finish_decl (decl,
+ build_x_indirect_ref (input_location, begin, RO_UNARY_STAR,
+ tf_warning_or_error),
+ /*is_constant_init*/false, NULL_TREE,
+ LOOKUP_ONLYCONVERTING);
+ if (VAR_P (decl) && DECL_DECOMPOSITION_P (decl))
+ cp_finish_decomp (decl, decomp_first_name, decomp_cnt);
+}
+
/* Parse the restricted form of the for statement allowed by OpenMP. */
static tree
tree *cclauses, bool *if_p)
{
tree init, orig_init, cond, incr, body, decl, pre_body = NULL_TREE, ret;
- tree real_decl, initv, condv, incrv, declv;
+ tree orig_decl;
+ tree real_decl, initv, condv, incrv, declv, orig_declv;
tree this_pre_body, cl, ordered_cl = NULL_TREE;
location_t loc_first;
bool collapse_err = false;
initv = make_tree_vec (count);
condv = make_tree_vec (count);
incrv = make_tree_vec (count);
+ orig_declv = NULL_TREE;
loc_first = cp_lexer_peek_token (parser->lexer)->location;
}
loc = cp_lexer_consume_token (parser->lexer)->location;
+ /* Don't create location wrapper nodes within an OpenMP "for"
+ statement. */
+ auto_suppress_location_wrappers sentinel;
+
matching_parens parens;
if (!parens.require_open (parser))
return NULL;
- init = orig_init = decl = real_decl = NULL;
+ init = orig_init = decl = real_decl = orig_decl = NULL_TREE;
this_pre_body = push_stmt_list ();
+ if (code != OACC_LOOP && cxx_dialect >= cxx11)
+ {
+ /* Save tokens so that we can put them back. */
+ cp_lexer_save_tokens (parser->lexer);
+
+ /* Look for ':' that is not nested in () or {}. */
+ bool is_range_for
+ = (cp_parser_skip_to_closing_parenthesis_1 (parser,
+ /*recovering=*/false,
+ CPP_COLON,
+ /*consume_paren=*/
+ false) == -1);
+
+ /* Roll back the tokens we skipped. */
+ cp_lexer_rollback_tokens (parser->lexer);
+
+ if (is_range_for)
+ {
+ bool saved_colon_corrects_to_scope_p
+ = parser->colon_corrects_to_scope_p;
+
+ /* A colon is used in range-based for. */
+ parser->colon_corrects_to_scope_p = false;
+
+ /* Parse the declaration. */
+ cp_parser_simple_declaration (parser,
+ /*function_definition_allowed_p=*/
+ false, &decl);
+ parser->colon_corrects_to_scope_p
+ = saved_colon_corrects_to_scope_p;
+
+ cp_parser_require (parser, CPP_COLON, RT_COLON);
+
+ init = cp_parser_range_for (parser, NULL_TREE, NULL_TREE, decl,
+ false, 0, true);
+
+ cp_convert_omp_range_for (this_pre_body, for_block, decl,
+ orig_decl, init, orig_init,
+ cond, incr);
+ if (this_pre_body)
+ {
+ if (pre_body)
+ {
+ tree t = pre_body;
+ pre_body = push_stmt_list ();
+ add_stmt (t);
+ add_stmt (this_pre_body);
+ pre_body = pop_stmt_list (pre_body);
+ }
+ else
+ pre_body = this_pre_body;
+ }
+
+ if (ordered_cl)
+ error_at (OMP_CLAUSE_LOCATION (ordered_cl),
+ "%<ordered%> clause with parameter on "
+ "range-based %<for%> loop");
+
+ goto parse_close_paren;
+ }
+ }
+
add_private_clause
= cp_parser_omp_for_loop_init (parser, this_pre_body, for_block,
init, orig_init, decl, real_decl);
error_at (loc, "iteration variable %qD "
"should not be firstprivate",
decl);
- else if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_REDUCTION
+ else if ((OMP_CLAUSE_CODE (c) == OMP_CLAUSE_REDUCTION
+ || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_IN_REDUCTION)
&& OMP_CLAUSE_DECL (c) == decl)
error_at (loc, "iteration variable %qD should not be reduction",
decl);
cond = NULL;
if (cp_lexer_next_token_is_not (parser->lexer, CPP_SEMICOLON))
- cond = cp_parser_omp_for_cond (parser, decl);
+ cond = cp_parser_omp_for_cond (parser, decl, code);
cp_parser_require (parser, CPP_SEMICOLON, RT_SEMICOLON);
incr = NULL;
protected_set_expr_location (incr, input_location);
}
+ parse_close_paren:
if (!parens.require_close (parser))
cp_parser_skip_to_closing_parenthesis (parser, /*recovering=*/true,
/*or_comma=*/false,
orig_inits.safe_grow_cleared (i + 1);
orig_inits[i] = orig_init;
}
+ if (orig_decl)
+ {
+ if (!orig_declv)
+ orig_declv = copy_node (declv);
+ TREE_VEC_ELT (orig_declv, i) = orig_decl;
+ }
+ else if (orig_declv)
+ TREE_VEC_ELT (orig_declv, i) = decl;
if (i == count - 1)
break;
/* Note that the grammar doesn't call for a structured block here,
though the loop as a whole is a structured block. */
- body = push_stmt_list ();
+ if (orig_declv)
+ {
+ body = begin_omp_structured_block ();
+ for (i = 0; i < count; i++)
+ if (TREE_VEC_ELT (orig_declv, i) != TREE_VEC_ELT (declv, i))
+ cp_finish_omp_range_for (TREE_VEC_ELT (orig_declv, i),
+ TREE_VEC_ELT (declv, i));
+ }
+ else
+ body = push_stmt_list ();
cp_parser_statement (parser, NULL_TREE, false, if_p);
- body = pop_stmt_list (body);
+ if (orig_declv)
+ body = finish_omp_structured_block (body);
+ else
+ body = pop_stmt_list (body);
if (declv == NULL_TREE)
ret = NULL_TREE;
else
- ret = finish_omp_for (loc_first, code, declv, NULL, initv, condv, incrv,
- body, pre_body, &orig_inits, clauses);
+ ret = finish_omp_for (loc_first, code, declv, orig_declv, initv, condv,
+ incrv, body, pre_body, &orig_inits, clauses);
while (nbraces)
{
| (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_COLLAPSE) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_IF) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NONTEMPORAL))
static tree
cp_parser_omp_simd (cp_parser *parser, cp_token *pragma_tok,
}
}
+ 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_SIMD, clauses, cclauses, if_p);
cp_parser_end_omp_structured_block (parser, save);
- add_stmt (finish_omp_structured_block (sb));
+ add_stmt (finish_omp_for_block (finish_omp_structured_block (sb), ret));
return ret;
}
clauses = cclauses[C_OMP_CLAUSE_SPLIT_FOR];
}
+ 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_FOR, clauses, cclauses, if_p);
cp_parser_end_omp_structured_block (parser, save);
- add_stmt (finish_omp_structured_block (sb));
+ add_stmt (finish_omp_for_block (finish_omp_structured_block (sb), ret));
return ret;
}
+static tree cp_parser_omp_taskloop (cp_parser *, cp_token *, char *,
+ omp_clause_mask, tree *, bool *);
+
/* OpenMP 2.5:
# pragma omp master new-line
structured-block */
static tree
-cp_parser_omp_master (cp_parser *parser, cp_token *pragma_tok, bool *if_p)
+cp_parser_omp_master (cp_parser *parser, cp_token *pragma_tok,
+ char *p_name, omp_clause_mask mask, tree *cclauses,
+ bool *if_p)
{
- cp_parser_require_pragma_eol (parser, pragma_tok);
- return c_finish_omp_master (input_location,
+ tree clauses, sb, ret;
+ unsigned int save;
+ location_t loc = cp_lexer_peek_token (parser->lexer)->location;
+
+ strcat (p_name, " master");
+
+ 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, "taskloop") == 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_taskloop (parser, pragma_tok, p_name, mask,
+ cclauses, if_p);
+ sb = begin_omp_structured_block ();
+ save = cp_parser_begin_omp_structured_block (parser);
+ ret = cp_parser_omp_taskloop (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;
+ return c_finish_omp_master (loc, body);
+ }
+ }
+ if (!flag_openmp) /* flag_openmp_simd */
+ {
+ cp_parser_skip_to_pragma_eol (parser, pragma_tok);
+ return NULL_TREE;
+ }
+
+ if (cclauses)
+ {
+ clauses = cp_parser_omp_all_clauses (parser, mask, p_name, pragma_tok,
+ false);
+ cp_omp_split_clauses (loc, OMP_MASTER, mask, clauses, cclauses);
+ }
+ else
+ cp_parser_require_pragma_eol (parser, pragma_tok);
+
+ return c_finish_omp_master (loc,
cp_parser_omp_structured_block (parser, if_p));
}
cp_parser_skip_to_pragma_eol (parser, pragma_tok);
return NULL_TREE;
}
- else if (!flag_openmp) /* flag_openmp_simd */
- {
- 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))
{
tree id = cp_lexer_peek_token (parser->lexer)->u.value;
const char *p = IDENTIFIER_POINTER (id);
- if (strcmp (p, "sections") == 0)
+ if (strcmp (p, "master") == 0)
+ {
+ tree cclauses_buf[C_OMP_CLAUSE_SPLIT_COUNT];
+ cclauses = cclauses_buf;
+
+ cp_lexer_consume_token (parser->lexer);
+ block = begin_omp_parallel ();
+ save = cp_parser_begin_omp_structured_block (parser);
+ tree ret = cp_parser_omp_master (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);
+ OMP_PARALLEL_COMBINED (stmt) = 1;
+ if (ret == NULL_TREE)
+ return ret;
+ 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)
{
tree cclauses_buf[C_OMP_CLAUSE_SPLIT_COUNT];
cclauses = cclauses_buf;
return stmt;
}
}
+ else if (!flag_openmp) /* flag_openmp_simd */
+ {
+ cp_parser_skip_to_pragma_eol (parser, pragma_tok);
+ return NULL_TREE;
+ }
clauses = cp_parser_omp_all_clauses (parser, mask, p_name, pragma_tok,
cclauses == NULL);
{
tree stmt = make_node (OMP_SINGLE);
TREE_TYPE (stmt) = void_type_node;
+ SET_EXPR_LOCATION (stmt, pragma_tok->location);
OMP_SINGLE_CLAUSES (stmt)
= cp_parser_omp_all_clauses (parser, OMP_SINGLE_CLAUSE_MASK,
| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FINAL) \
| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_MERGEABLE) \
| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEPEND) \
- | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PRIORITY))
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PRIORITY) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_IN_REDUCTION))
static tree
cp_parser_omp_task (cp_parser *parser, cp_token *pragma_tok, bool *if_p)
}
/* OpenMP 3.0:
- # pragma omp taskwait new-line */
+ # pragma omp taskwait new-line
+
+ OpenMP 5.0:
+ # pragma omp taskwait taskwait-clause[opt] new-line */
+
+#define OMP_TASKWAIT_CLAUSE_MASK \
+ (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEPEND)
static void
cp_parser_omp_taskwait (cp_parser *parser, cp_token *pragma_tok)
{
- cp_parser_require_pragma_eol (parser, pragma_tok);
- finish_omp_taskwait ();
+ tree clauses
+ = cp_parser_omp_all_clauses (parser, OMP_TASKWAIT_CLAUSE_MASK,
+ "#pragma omp taskwait", pragma_tok);
+
+ if (clauses)
+ {
+ tree stmt = make_node (OMP_TASK);
+ TREE_TYPE (stmt) = void_node;
+ OMP_TASK_CLAUSES (stmt) = clauses;
+ OMP_TASK_BODY (stmt) = NULL_TREE;
+ SET_EXPR_LOCATION (stmt, pragma_tok->location);
+ add_stmt (stmt);
+ }
+ else
+ finish_omp_taskwait ();
}
/* OpenMP 3.1:
/* OpenMP 4.0:
# pragma omp taskgroup new-line
- structured-block */
+ structured-block
+
+ OpenMP 5.0:
+ # pragma omp taskgroup taskgroup-clause[optseq] new-line */
+
+#define OMP_TASKGROUP_CLAUSE_MASK \
+ ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_TASK_REDUCTION))
static tree
cp_parser_omp_taskgroup (cp_parser *parser, cp_token *pragma_tok, bool *if_p)
{
- cp_parser_require_pragma_eol (parser, pragma_tok);
+ tree clauses
+ = cp_parser_omp_all_clauses (parser, OMP_TASKGROUP_CLAUSE_MASK,
+ "#pragma omp taskgroup", pragma_tok);
return c_finish_omp_taskgroup (input_location,
cp_parser_omp_structured_block (parser,
- if_p));
+ if_p),
+ clauses);
}
clauses = cclauses[C_OMP_CLAUSE_SPLIT_DISTRIBUTE];
}
+ 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_DISTRIBUTE, clauses, NULL, if_p);
cp_parser_end_omp_structured_block (parser, save);
- add_stmt (finish_omp_structured_block (sb));
+ add_stmt (finish_omp_for_block (finish_omp_structured_block (sb), ret));
return ret;
}
if (!flag_openmp) /* flag_openmp_simd */
return cp_parser_omp_distribute (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_distribute (parser, pragma_tok, p_name, mask,
tree stmt = make_node (OMP_TEAMS);
TREE_TYPE (stmt) = void_type_node;
OMP_TEAMS_CLAUSES (stmt) = clauses;
+ keep_next_level (true);
OMP_TEAMS_BODY (stmt) = cp_parser_omp_structured_block (parser, if_p);
SET_EXPR_LOCATION (stmt, loc);
*pc = OMP_CLAUSE_CHAIN (*pc);
continue;
}
+ else if (OMP_CLAUSE_CODE (*pc) == OMP_CLAUSE_USE_DEVICE_PTR)
+ 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%> clause");
+ "one %<map%> or %<use_device_ptr%> clause");
return NULL_TREE;
}
{
tree *pc = NULL, stmt;
+ if (flag_openmp)
+ omp_requires_mask
+ = (enum omp_requires) (omp_requires_mask | OMP_REQUIRES_TARGET_USED);
+
if (cp_lexer_next_token_is (parser->lexer, CPP_NAME))
{
tree id = cp_lexer_peek_token (parser->lexer)->u.value;
| (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_CREATE) \
| (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_DEVICEPTR) \
| (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_IF) \
- | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_PRESENT) \
- | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_PRESENT_OR_COPY) \
- | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_PRESENT_OR_COPYIN) \
- | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_PRESENT_OR_COPYOUT) \
- | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_PRESENT_OR_CREATE))
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_PRESENT) )
static tree
cp_parser_oacc_data (cp_parser *parser, cp_token *pragma_tok, bool *if_p)
| (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_DEVICEPTR) \
| (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_DEVICE_RESIDENT) \
| (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_LINK) \
- | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_PRESENT) \
- | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_PRESENT_OR_COPY) \
- | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_PRESENT_OR_COPYIN) \
- | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_PRESENT_OR_COPYOUT) \
- | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_PRESENT_OR_CREATE))
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_PRESENT) )
static tree
cp_parser_oacc_declare (cp_parser *parser, cp_token *pragma_tok)
switch (OMP_CLAUSE_MAP_KIND (t))
{
case GOMP_MAP_FIRSTPRIVATE_POINTER:
- case GOMP_MAP_FORCE_ALLOC:
- case GOMP_MAP_FORCE_TO:
+ case GOMP_MAP_ALLOC:
+ case GOMP_MAP_TO:
case GOMP_MAP_FORCE_DEVICEPTR:
case GOMP_MAP_DEVICE_RESIDENT:
break;
| (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_ASYNC) \
| (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_COPYIN) \
| (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_CREATE) \
- | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_PRESENT_OR_COPYIN) \
- | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_PRESENT_OR_CREATE) \
| (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_WAIT) )
#define OACC_EXIT_DATA_CLAUSE_MASK \
| (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_ASYNC) \
| (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_COPYOUT) \
| (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_DELETE) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_FINALIZE) \
| (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_WAIT) )
static tree
stmt = enter ? make_node (OACC_ENTER_DATA) : make_node (OACC_EXIT_DATA);
TREE_TYPE (stmt) = void_type_node;
OMP_STANDALONE_CLAUSES (stmt) = clauses;
- SET_EXPR_LOCATION (stmt, pragma_tok->location);
+ SET_EXPR_LOCATION (stmt, loc);
add_stmt (stmt);
return stmt;
}
| (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_NUM_GANGS) \
| (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_NUM_WORKERS) \
| (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_PRESENT) \
- | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_PRESENT_OR_COPY) \
- | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_PRESENT_OR_COPYIN) \
- | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_PRESENT_OR_COPYOUT) \
- | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_PRESENT_OR_CREATE) \
| (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_VECTOR_LENGTH) \
| (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_WAIT) )
| (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_NUM_GANGS) \
| (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_NUM_WORKERS) \
| (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_PRESENT) \
- | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_PRESENT_OR_COPY) \
- | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_PRESENT_OR_COPYIN) \
- | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_PRESENT_OR_COPYOUT) \
- | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_PRESENT_OR_CREATE) \
| (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_PRIVATE) \
| (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_REDUCTION) \
| (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_VECTOR_LENGTH) \
cp_lexer_consume_token (parser->lexer);
tree block = begin_omp_parallel ();
tree clauses;
- cp_parser_oacc_loop (parser, pragma_tok, p_name, mask, &clauses,
- if_p);
+ tree stmt = cp_parser_oacc_loop (parser, pragma_tok, p_name, mask,
+ &clauses, if_p);
+ protected_set_expr_location (stmt, pragma_tok->location);
return finish_omp_construct (code, block, clauses);
}
}
| (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_DEVICE) \
| (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_HOST) \
| (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_IF) \
- | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_SELF) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_IF_PRESENT) \
| (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_WAIT))
static tree
else
{
cp_parser_parse_tentatively (parser);
+ /* Don't create location wrapper nodes here. */
+ auto_suppress_location_wrappers sentinel;
tree fn_name = cp_parser_id_expression (parser, /*template_p=*/false,
/*check_dependency_p=*/true,
/*template_p=*/NULL,
return false;
}
+/* OpenMP 5.0
+ #pragma omp requires clauses[optseq] new-line */
+
+static bool
+cp_parser_omp_requires (cp_parser *parser, cp_token *pragma_tok)
+{
+ bool first = true;
+ enum omp_requires new_req = (enum omp_requires) 0;
+
+ location_t loc = pragma_tok->location;
+ while (cp_lexer_next_token_is_not (parser->lexer, CPP_PRAGMA_EOL))
+ {
+ if (!first && cp_lexer_next_token_is (parser->lexer, CPP_COMMA))
+ cp_lexer_consume_token (parser->lexer);
+
+ first = false;
+
+ 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);
+ location_t cloc = cp_lexer_peek_token (parser->lexer)->location;
+ enum omp_requires this_req = (enum omp_requires) 0;
+
+ if (!strcmp (p, "unified_address"))
+ this_req = OMP_REQUIRES_UNIFIED_ADDRESS;
+ else if (!strcmp (p, "unified_shared_memory"))
+ this_req = OMP_REQUIRES_UNIFIED_SHARED_MEMORY;
+ else if (!strcmp (p, "dynamic_allocators"))
+ this_req = OMP_REQUIRES_DYNAMIC_ALLOCATORS;
+ else if (!strcmp (p, "reverse_offload"))
+ this_req = OMP_REQUIRES_REVERSE_OFFLOAD;
+ else if (!strcmp (p, "atomic_default_mem_order"))
+ {
+ cp_lexer_consume_token (parser->lexer);
+
+ matching_parens parens;
+ if (parens.require_open (parser))
+ {
+ if (cp_lexer_next_token_is (parser->lexer, CPP_NAME))
+ {
+ id = cp_lexer_peek_token (parser->lexer)->u.value;
+ p = IDENTIFIER_POINTER (id);
+
+ if (!strcmp (p, "seq_cst"))
+ this_req
+ = (enum omp_requires) OMP_MEMORY_ORDER_SEQ_CST;
+ else if (!strcmp (p, "relaxed"))
+ this_req
+ = (enum omp_requires) OMP_MEMORY_ORDER_RELAXED;
+ else if (!strcmp (p, "acq_rel"))
+ this_req
+ = (enum omp_requires) OMP_MEMORY_ORDER_ACQ_REL;
+ }
+ if (this_req == 0)
+ {
+ error_at (cp_lexer_peek_token (parser->lexer)->location,
+ "expected %<seq_cst%>, %<relaxed%> or "
+ "%<acq_rel%>");
+ if (cp_lexer_nth_token_is (parser->lexer, 2,
+ CPP_CLOSE_PAREN))
+ cp_lexer_consume_token (parser->lexer);
+ }
+ else
+ cp_lexer_consume_token (parser->lexer);
+
+ if (!parens.require_close (parser))
+ cp_parser_skip_to_closing_parenthesis (parser,
+ /*recovering=*/true,
+ /*or_comma=*/false,
+ /*consume_paren=*/
+ true);
+
+ if (this_req == 0)
+ {
+ cp_parser_require_pragma_eol (parser, pragma_tok);
+ return false;
+ }
+ }
+ p = NULL;
+ }
+ else
+ {
+ error_at (cloc, "expected %<unified_address%>, "
+ "%<unified_shared_memory%>, "
+ "%<dynamic_allocators%>, "
+ "%<reverse_offload%> "
+ "or %<atomic_default_mem_order%> clause");
+ cp_parser_skip_to_pragma_eol (parser, pragma_tok);
+ return false;
+ }
+ if (p)
+ sorry_at (cloc, "%qs clause on %<requires%> directive not "
+ "supported yet", p);
+ if (p)
+ cp_lexer_consume_token (parser->lexer);
+ if (this_req)
+ {
+ if ((this_req & ~OMP_REQUIRES_ATOMIC_DEFAULT_MEM_ORDER) != 0)
+ {
+ if ((this_req & new_req) != 0)
+ error_at (cloc, "too many %qs clauses", p);
+ if (this_req != OMP_REQUIRES_DYNAMIC_ALLOCATORS
+ && (omp_requires_mask & OMP_REQUIRES_TARGET_USED) != 0)
+ error_at (cloc, "%qs clause used lexically after first "
+ "target construct or offloading API", p);
+ }
+ else if ((new_req & OMP_REQUIRES_ATOMIC_DEFAULT_MEM_ORDER) != 0)
+ {
+ error_at (cloc, "too many %qs clauses",
+ "atomic_default_mem_order");
+ this_req = (enum omp_requires) 0;
+ }
+ else if ((omp_requires_mask
+ & OMP_REQUIRES_ATOMIC_DEFAULT_MEM_ORDER) != 0)
+ {
+ error_at (cloc, "more than one %<atomic_default_mem_order%>"
+ " clause in a single compilation unit");
+ this_req
+ = (enum omp_requires)
+ (omp_requires_mask
+ & OMP_REQUIRES_ATOMIC_DEFAULT_MEM_ORDER);
+ }
+ else if ((omp_requires_mask
+ & OMP_REQUIRES_ATOMIC_DEFAULT_MEM_ORDER_USED) != 0)
+ error_at (cloc, "%<atomic_default_mem_order%> clause used "
+ "lexically after first %<atomic%> construct "
+ "without memory order clause");
+ new_req = (enum omp_requires) (new_req | this_req);
+ omp_requires_mask
+ = (enum omp_requires) (omp_requires_mask | this_req);
+ continue;
+ }
+ }
+ break;
+ }
+ cp_parser_require_pragma_eol (parser, pragma_tok);
+
+ if (new_req == 0)
+ error_at (loc, "%<pragma omp requires%> requires at least one clause");
+ return false;
+}
+
+
/* OpenMP 4.5:
#pragma omp taskloop taskloop-clause[optseq] new-line
for-loop
| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FINAL) \
| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_MERGEABLE) \
| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOGROUP) \
- | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PRIORITY))
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PRIORITY) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_REDUCTION) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_IN_REDUCTION))
static tree
cp_parser_omp_taskloop (cp_parser *parser, cp_token *pragma_tok,
strcat (p_name, " taskloop");
mask |= OMP_TASKLOOP_CLAUSE_MASK;
+ /* #pragma omp parallel master taskloop{, simd} disallow in_reduction
+ clause. */
+ if ((mask & (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NUM_THREADS)) != 0)
+ mask &= ~(OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_IN_REDUCTION);
if (cp_lexer_next_token_is (parser->lexer, CPP_NAME))
{
clauses = cclauses[C_OMP_CLAUSE_SPLIT_TASKLOOP];
}
+ keep_next_level (true);
sb = begin_omp_structured_block ();
save = cp_parser_begin_omp_structured_block (parser);
if_p);
cp_parser_end_omp_structured_block (parser, save);
- add_stmt (finish_omp_structured_block (sb));
+ add_stmt (finish_omp_for_block (finish_omp_structured_block (sb), ret));
return ret;
}
if_p);
break;
case PRAGMA_OMP_MASTER:
- stmt = cp_parser_omp_master (parser, pragma_tok, if_p);
+ strcpy (p_name, "#pragma omp");
+ stmt = cp_parser_omp_master (parser, pragma_tok, p_name, mask, NULL,
+ if_p);
break;
case PRAGMA_OMP_PARALLEL:
strcpy (p_name, "#pragma omp");
}
break;
+ case PRAGMA_OMP_DEPOBJ:
+ switch (context)
+ {
+ case pragma_compound:
+ cp_parser_omp_depobj (parser, pragma_tok);
+ return false;
+ case pragma_stmt:
+ error_at (pragma_tok->location, "%<#pragma %s%> may only be "
+ "used in compound statements", "omp depobj");
+ break;
+ default:
+ goto bad_stmt;
+ }
+ break;
+
case PRAGMA_OMP_FLUSH:
switch (context)
{
pop_omp_privatization_clauses (stmt);
return true;
+ case PRAGMA_OMP_REQUIRES:
+ return cp_parser_omp_requires (parser, pragma_tok);
+
case PRAGMA_OMP_ORDERED:
if (context != pragma_stmt && context != pragma_compound)
goto bad_stmt;
? dk_no_deferred : dk_no_check);
cp_parser_translation_unit (the_parser);
the_parser = NULL;
+
+ finish_translation_unit ();
}
/* Create an identifier for a generic parameter type (a synthesized