blob: 2235da10c7c4d8603de636682c3f7ea83f2c6459 [file] [log] [blame]
/* -*- C++ -*- Parser.
Copyright (C) 2000-2022 Free Software Foundation, Inc.
Written by Mark Mitchell <mark@codesourcery.com>.
This file is part of GCC.
GCC is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3, or (at your option)
any later version.
GCC is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>. */
#include "config.h"
#define INCLUDE_MEMORY
#include "system.h"
#include "coretypes.h"
#include "cp-tree.h"
#include "c-family/c-common.h"
#include "timevar.h"
#include "stringpool.h"
#include "cgraph.h"
#include "print-tree.h"
#include "attribs.h"
#include "trans-mem.h"
#include "intl.h"
#include "decl.h"
#include "c-family/c-objc.h"
#include "plugin.h"
#include "tree-pretty-print.h"
#include "parser.h"
#include "gomp-constants.h"
#include "omp-general.h"
#include "omp-offload.h"
#include "c-family/c-indentation.h"
#include "context.h"
#include "gcc-rich-location.h"
#include "tree-iterator.h"
#include "cp-name-hint.h"
#include "memmodel.h"
#include "c-family/known-headers.h"
/* The lexer. */
/* The cp_lexer_* routines mediate between the lexer proper (in libcpp
and c-lex.cc) and the C++ parser. */
/* The various kinds of non integral constant we encounter. */
enum non_integral_constant {
NIC_NONE,
/* floating-point literal */
NIC_FLOAT,
/* %<this%> */
NIC_THIS,
/* %<__FUNCTION__%> */
NIC_FUNC_NAME,
/* %<__PRETTY_FUNCTION__%> */
NIC_PRETTY_FUNC,
/* %<__func__%> */
NIC_C99_FUNC,
/* "%<va_arg%> */
NIC_VA_ARG,
/* a cast */
NIC_CAST,
/* %<typeid%> operator */
NIC_TYPEID,
/* non-constant compound literals */
NIC_NCC,
/* a function call */
NIC_FUNC_CALL,
/* an increment */
NIC_INC,
/* an decrement */
NIC_DEC,
/* an array reference */
NIC_ARRAY_REF,
/* %<->%> */
NIC_ARROW,
/* %<.%> */
NIC_POINT,
/* the address of a label */
NIC_ADDR_LABEL,
/* %<*%> */
NIC_STAR,
/* %<&%> */
NIC_ADDR,
/* %<++%> */
NIC_PREINCREMENT,
/* %<--%> */
NIC_PREDECREMENT,
/* %<new%> */
NIC_NEW,
/* %<delete%> */
NIC_DEL,
/* calls to overloaded operators */
NIC_OVERLOADED,
/* an assignment */
NIC_ASSIGNMENT,
/* a comma operator */
NIC_COMMA,
/* a call to a constructor */
NIC_CONSTRUCTOR,
/* a transaction expression */
NIC_TRANSACTION
};
/* The various kinds of errors about name-lookup failing. */
enum name_lookup_error {
/* NULL */
NLE_NULL,
/* is not a type */
NLE_TYPE,
/* is not a class or namespace */
NLE_CXX98,
/* is not a class, namespace, or enumeration */
NLE_NOT_CXX98
};
/* The various kinds of required token */
enum required_token {
RT_NONE,
RT_SEMICOLON, /* ';' */
RT_OPEN_PAREN, /* '(' */
RT_CLOSE_BRACE, /* '}' */
RT_OPEN_BRACE, /* '{' */
RT_CLOSE_SQUARE, /* ']' */
RT_OPEN_SQUARE, /* '[' */
RT_COMMA, /* ',' */
RT_SCOPE, /* '::' */
RT_LESS, /* '<' */
RT_GREATER, /* '>' */
RT_EQ, /* '=' */
RT_ELLIPSIS, /* '...' */
RT_MULT, /* '*' */
RT_COMPL, /* '~' */
RT_COLON, /* ':' */
RT_COLON_SCOPE, /* ':' or '::' */
RT_CLOSE_PAREN, /* ')' */
RT_COMMA_CLOSE_PAREN, /* ',' or ')' */
RT_PRAGMA_EOL, /* end of line */
RT_NAME, /* identifier */
/* The type is CPP_KEYWORD */
RT_NEW, /* new */
RT_DELETE, /* delete */
RT_RETURN, /* return */
RT_WHILE, /* while */
RT_EXTERN, /* extern */
RT_STATIC_ASSERT, /* static_assert */
RT_DECLTYPE, /* decltype */
RT_OPERATOR, /* operator */
RT_CLASS, /* class */
RT_TEMPLATE, /* template */
RT_NAMESPACE, /* namespace */
RT_USING, /* using */
RT_ASM, /* asm */
RT_TRY, /* try */
RT_CATCH, /* catch */
RT_THROW, /* throw */
RT_AUTO, /* auto */
RT_LABEL, /* __label__ */
RT_AT_TRY, /* @try */
RT_AT_SYNCHRONIZED, /* @synchronized */
RT_AT_THROW, /* @throw */
RT_SELECT, /* selection-statement */
RT_ITERATION, /* iteration-statement */
RT_JUMP, /* jump-statement */
RT_CLASS_KEY, /* class-key */
RT_CLASS_TYPENAME_TEMPLATE, /* class, typename, or template */
RT_TRANSACTION_ATOMIC, /* __transaction_atomic */
RT_TRANSACTION_RELAXED, /* __transaction_relaxed */
RT_TRANSACTION_CANCEL, /* __transaction_cancel */
RT_CO_YIELD /* co_yield */
};
/* RAII wrapper for parser->in_type_id_in_expr_p, setting it on creation and
reverting it on destruction. */
class type_id_in_expr_sentinel
{
cp_parser *parser;
bool saved;
public:
type_id_in_expr_sentinel (cp_parser *parser, bool set = true)
: parser (parser),
saved (parser->in_type_id_in_expr_p)
{ parser->in_type_id_in_expr_p = set; }
~type_id_in_expr_sentinel ()
{ parser->in_type_id_in_expr_p = saved; }
};
/* Prototypes. */
static cp_lexer *cp_lexer_new_main
(void);
static cp_lexer *cp_lexer_new_from_tokens
(cp_token_cache *tokens);
static void cp_lexer_destroy
(cp_lexer *);
static int cp_lexer_saving_tokens
(const cp_lexer *);
static cp_token *cp_lexer_token_at
(cp_lexer *, cp_token_position);
static void cp_lexer_get_preprocessor_token
(unsigned, cp_token *);
static inline cp_token *cp_lexer_peek_token
(cp_lexer *);
static cp_token *cp_lexer_peek_nth_token
(cp_lexer *, size_t);
static inline bool cp_lexer_next_token_is
(cp_lexer *, enum cpp_ttype);
static bool cp_lexer_next_token_is_not
(cp_lexer *, enum cpp_ttype);
static bool cp_lexer_next_token_is_keyword
(cp_lexer *, enum rid);
static cp_token *cp_lexer_consume_token
(cp_lexer *);
static void cp_lexer_purge_token
(cp_lexer *);
static void cp_lexer_purge_tokens_after
(cp_lexer *, cp_token_position);
static void cp_lexer_save_tokens
(cp_lexer *);
static void cp_lexer_commit_tokens
(cp_lexer *);
static void cp_lexer_rollback_tokens
(cp_lexer *);
static void cp_lexer_print_token
(FILE *, cp_token *);
static inline bool cp_lexer_debugging_p
(cp_lexer *);
static void cp_lexer_start_debugging
(cp_lexer *) ATTRIBUTE_UNUSED;
static void cp_lexer_stop_debugging
(cp_lexer *) ATTRIBUTE_UNUSED;
static cp_token_cache *cp_token_cache_new
(cp_token *, cp_token *);
static tree cp_parser_late_noexcept_specifier
(cp_parser *, tree);
static void noexcept_override_late_checks
(tree, tree);
static void cp_parser_initial_pragma
(cp_token *);
static bool cp_parser_omp_declare_reduction_exprs
(tree, cp_parser *);
static void cp_finalize_oacc_routine
(cp_parser *, tree, bool);
/* Manifest constants. */
#define CP_LEXER_BUFFER_SIZE ((256 * 1024) / sizeof (cp_token))
#define CP_SAVED_TOKEN_STACK 5
/* Variables. */
/* The stream to which debugging output should be written. */
static FILE *cp_lexer_debug_stream;
/* Nonzero if we are parsing an unevaluated operand: an operand to
sizeof, typeof, or alignof. */
int cp_unevaluated_operand;
/* Dump up to NUM tokens in BUFFER to FILE starting with token
START_TOKEN. If START_TOKEN is NULL, the dump starts with the
first token in BUFFER. If NUM is 0, dump all the tokens. If
CURR_TOKEN is set and it is one of the tokens in BUFFER, it will be
highlighted by surrounding it in [[ ]]. */
static void
cp_lexer_dump_tokens (FILE *file, vec<cp_token, va_gc> *buffer,
cp_token *start_token, unsigned num,
cp_token *curr_token)
{
unsigned i, nprinted;
cp_token *token;
bool do_print;
fprintf (file, "%u tokens\n", vec_safe_length (buffer));
if (buffer == NULL)
return;
if (num == 0)
num = buffer->length ();
if (start_token == NULL)
start_token = buffer->address ();
if (start_token > buffer->address ())
{
cp_lexer_print_token (file, &(*buffer)[0]);
fprintf (file, " ... ");
}
do_print = false;
nprinted = 0;
for (i = 0; buffer->iterate (i, &token) && nprinted < num; i++)
{
if (token == start_token)
do_print = true;
if (!do_print)
continue;
nprinted++;
if (token == curr_token)
fprintf (file, "[[");
cp_lexer_print_token (file, token);
if (token == curr_token)
fprintf (file, "]]");
switch (token->type)
{
case CPP_SEMICOLON:
case CPP_OPEN_BRACE:
case CPP_CLOSE_BRACE:
case CPP_EOF:
fputc ('\n', file);
break;
default:
fputc (' ', file);
}
}
if (i == num && i < buffer->length ())
{
fprintf (file, " ... ");
cp_lexer_print_token (file, &buffer->last ());
}
fprintf (file, "\n");
}
/* Dump all tokens in BUFFER to stderr. */
void
cp_lexer_debug_tokens (vec<cp_token, va_gc> *buffer)
{
cp_lexer_dump_tokens (stderr, buffer, NULL, 0, NULL);
}
DEBUG_FUNCTION void
debug (vec<cp_token, va_gc> &ref)
{
cp_lexer_dump_tokens (stderr, &ref, NULL, 0, NULL);
}
DEBUG_FUNCTION void
debug (vec<cp_token, va_gc> *ptr)
{
if (ptr)
debug (*ptr);
else
fprintf (stderr, "<nil>\n");
}
/* Dump the cp_parser tree field T to FILE if T is non-NULL. DESC is the
description for T. */
static void
cp_debug_print_tree_if_set (FILE *file, const char *desc, tree t)
{
if (t)
{
fprintf (file, "%s: ", desc);
print_node_brief (file, "", t, 0);
}
}
/* Dump parser context C to FILE. */
static void
cp_debug_print_context (FILE *file, cp_parser_context *c)
{
const char *status_s[] = { "OK", "ERROR", "COMMITTED" };
fprintf (file, "{ status = %s, scope = ", status_s[c->status]);
print_node_brief (file, "", c->object_type, 0);
fprintf (file, "}\n");
}
/* Print the stack of parsing contexts to FILE starting with FIRST. */
static void
cp_debug_print_context_stack (FILE *file, cp_parser_context *first)
{
unsigned i;
cp_parser_context *c;
fprintf (file, "Parsing context stack:\n");
for (i = 0, c = first; c; c = c->next, i++)
{
fprintf (file, "\t#%u: ", i);
cp_debug_print_context (file, c);
}
}
/* Print the value of FLAG to FILE. DESC is a string describing the flag. */
static void
cp_debug_print_flag (FILE *file, const char *desc, bool flag)
{
if (flag)
fprintf (file, "%s: true\n", desc);
}
/* Print an unparsed function entry UF to FILE. */
static void
cp_debug_print_unparsed_function (FILE *file, cp_unparsed_functions_entry *uf)
{
unsigned i;
cp_default_arg_entry *default_arg_fn;
tree fn;
fprintf (file, "\tFunctions with default args:\n");
for (i = 0;
vec_safe_iterate (uf->funs_with_default_args, i, &default_arg_fn);
i++)
{
fprintf (file, "\t\tClass type: ");
print_node_brief (file, "", default_arg_fn->class_type, 0);
fprintf (file, "\t\tDeclaration: ");
print_node_brief (file, "", default_arg_fn->decl, 0);
fprintf (file, "\n");
}
fprintf (file, "\n\tFunctions with definitions that require "
"post-processing\n\t\t");
for (i = 0; vec_safe_iterate (uf->funs_with_definitions, i, &fn); i++)
{
print_node_brief (file, "", fn, 0);
fprintf (file, " ");
}
fprintf (file, "\n");
fprintf (file, "\n\tNon-static data members with initializers that require "
"post-processing\n\t\t");
for (i = 0; vec_safe_iterate (uf->nsdmis, i, &fn); i++)
{
print_node_brief (file, "", fn, 0);
fprintf (file, " ");
}
fprintf (file, "\n");
}
/* Print the stack of unparsed member functions S to FILE. */
static void
cp_debug_print_unparsed_queues (FILE *file,
vec<cp_unparsed_functions_entry, va_gc> *s)
{
unsigned i;
cp_unparsed_functions_entry *uf;
fprintf (file, "Unparsed functions\n");
for (i = 0; vec_safe_iterate (s, i, &uf); i++)
{
fprintf (file, "#%u:\n", i);
cp_debug_print_unparsed_function (file, uf);
}
}
/* Dump the tokens in a window of size WINDOW_SIZE around the next_token for
the given PARSER. If FILE is NULL, the output is printed on stderr. */
static void
cp_debug_parser_tokens (FILE *file, cp_parser *parser, int window_size)
{
cp_token *next_token, *first_token, *start_token;
if (file == NULL)
file = stderr;
next_token = parser->lexer->next_token;
first_token = parser->lexer->buffer->address ();
start_token = (next_token > first_token + window_size / 2)
? next_token - window_size / 2
: first_token;
cp_lexer_dump_tokens (file, parser->lexer->buffer, start_token, window_size,
next_token);
}
/* Dump debugging information for the given PARSER. If FILE is NULL,
the output is printed on stderr. */
void
cp_debug_parser (FILE *file, cp_parser *parser)
{
const size_t window_size = 20;
cp_token *token;
expanded_location eloc;
if (file == NULL)
file = stderr;
fprintf (file, "Parser state\n\n");
fprintf (file, "Number of tokens: %u\n",
vec_safe_length (parser->lexer->buffer));
cp_debug_print_tree_if_set (file, "Lookup scope", parser->scope);
cp_debug_print_tree_if_set (file, "Object scope",
parser->object_scope);
cp_debug_print_tree_if_set (file, "Qualifying scope",
parser->qualifying_scope);
cp_debug_print_context_stack (file, parser->context);
cp_debug_print_flag (file, "Allow GNU extensions",
parser->allow_gnu_extensions_p);
cp_debug_print_flag (file, "'>' token is greater-than",
parser->greater_than_is_operator_p);
cp_debug_print_flag (file, "Default args allowed in current "
"parameter list", parser->default_arg_ok_p);
cp_debug_print_flag (file, "Parsing integral constant-expression",
parser->integral_constant_expression_p);
cp_debug_print_flag (file, "Allow non-constant expression in current "
"constant-expression",
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 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_declarator_p);
cp_debug_print_flag (file, "In template argument list",
parser->in_template_argument_list_p);
cp_debug_print_flag (file, "Parsing an iteration statement",
parser->in_statement & IN_ITERATION_STMT);
cp_debug_print_flag (file, "Parsing a switch statement",
parser->in_statement & IN_SWITCH_STMT);
cp_debug_print_flag (file, "Parsing a structured OpenMP block",
parser->in_statement & IN_OMP_BLOCK);
cp_debug_print_flag (file, "Parsing an OpenMP loop",
parser->in_statement & IN_OMP_FOR);
cp_debug_print_flag (file, "Parsing an if statement",
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, "String expressions should be translated "
"to execution character set",
parser->translate_strings_p);
cp_debug_print_flag (file, "Parsing function body outside of a "
"local class", parser->in_function_body);
cp_debug_print_flag (file, "Auto correct a colon to a scope operator",
parser->colon_corrects_to_scope_p);
cp_debug_print_flag (file, "Colon doesn't start a class definition",
parser->colon_doesnt_start_class_def_p);
cp_debug_print_flag (file, "Parsing an Objective-C++ message context",
parser->objective_c_message_context_p);
if (parser->type_definition_forbidden_message)
fprintf (file, "Error message for forbidden type definitions: %s %s\n",
parser->type_definition_forbidden_message,
parser->type_definition_forbidden_message_arg
? parser->type_definition_forbidden_message_arg : "<none>");
cp_debug_print_unparsed_queues (file, parser->unparsed_queues);
fprintf (file, "Number of class definitions in progress: %u\n",
parser->num_classes_being_defined);
fprintf (file, "Number of template parameter lists for the current "
"declaration: %u\n", parser->num_template_parameter_lists);
cp_debug_parser_tokens (file, parser, window_size);
token = parser->lexer->next_token;
fprintf (file, "Next token to parse:\n");
fprintf (file, "\tToken: ");
cp_lexer_print_token (file, token);
eloc = expand_location (token->location);
fprintf (file, "\n\tFile: %s\n", eloc.file);
fprintf (file, "\tLine: %d\n", eloc.line);
fprintf (file, "\tColumn: %d\n", eloc.column);
}
DEBUG_FUNCTION void
debug (cp_parser &ref)
{
cp_debug_parser (stderr, &ref);
}
DEBUG_FUNCTION void
debug (cp_parser *ptr)
{
if (ptr)
debug (*ptr);
else
fprintf (stderr, "<nil>\n");
}
/* Allocate memory for a new lexer object and return it. */
static cp_lexer *
cp_lexer_alloc (void)
{
/* Allocate the memory. */
cp_lexer *lexer = ggc_cleared_alloc<cp_lexer> ();
/* Initially we are not debugging. */
lexer->debugging_p = false;
lexer->saved_tokens.create (CP_SAVED_TOKEN_STACK);
/* Create the buffer. */
vec_alloc (lexer->buffer, CP_LEXER_BUFFER_SIZE);
return lexer;
}
/* Create a new main C++ lexer, the lexer that gets tokens from the
preprocessor. */
static cp_lexer *
cp_lexer_new_main (void)
{
cp_token token;
/* It's possible that parsing the first pragma will load a PCH file,
which is a GC collection point. So we have to do that before
allocating any memory. */
cp_lexer_get_preprocessor_token (0, &token);
cp_parser_initial_pragma (&token);
c_common_no_more_pch ();
cp_lexer *lexer = cp_lexer_alloc ();
/* Put the first token in the buffer. */
cp_token *tok = lexer->buffer->quick_push (token);
uintptr_t filter = 0;
if (modules_p ())
filter = module_token_cdtor (parse_in, filter);
/* Get the remaining tokens from the preprocessor. */
while (tok->type != CPP_EOF)
{
if (filter)
/* Process the previous token. */
module_token_lang (tok->type, tok->keyword, tok->u.value,
tok->location, filter);
tok = vec_safe_push (lexer->buffer, cp_token ());
cp_lexer_get_preprocessor_token (C_LEX_STRING_NO_JOIN, tok);
}
lexer->next_token = lexer->buffer->address ();
lexer->last_token = lexer->next_token
+ lexer->buffer->length ()
- 1;
if (lexer->buffer->length () != 1)
{
/* Set the EOF token's location to be the just after the previous
token's range. That way 'at-eof' diagnostics point at something
meaninful. */
auto range = get_range_from_loc (line_table, tok[-1].location);
tok[0].location
= linemap_position_for_loc_and_offset (line_table, range.m_finish, 1);
}
if (filter)
module_token_cdtor (parse_in, filter);
/* Subsequent preprocessor diagnostics should use compiler
diagnostic functions to get the compiler source location. */
done_lexing = true;
maybe_check_all_macros (parse_in);
gcc_assert (!lexer->next_token->purged_p);
return lexer;
}
/* Create a new lexer whose token stream is primed with the tokens in
CACHE. When these tokens are exhausted, no new tokens will be read. */
static cp_lexer *
cp_lexer_new_from_tokens (cp_token_cache *cache)
{
cp_token *first = cache->first;
cp_token *last = cache->last;
cp_lexer *lexer = ggc_cleared_alloc<cp_lexer> ();
/* We do not own the buffer. */
lexer->buffer = NULL;
/* Insert an EOF token. */
lexer->saved_type = last->type;
lexer->saved_keyword = last->keyword;
last->type = CPP_EOF;
last->keyword = RID_MAX;
lexer->next_token = first;
lexer->last_token = last;
lexer->saved_tokens.create (CP_SAVED_TOKEN_STACK);
/* Initially we are not debugging. */
lexer->debugging_p = false;
gcc_assert (!lexer->next_token->purged_p
&& !lexer->last_token->purged_p);
return lexer;
}
/* Frees all resources associated with LEXER. */
static void
cp_lexer_destroy (cp_lexer *lexer)
{
if (lexer->buffer)
vec_free (lexer->buffer);
else
{
/* Restore the token we overwrite with EOF. */
lexer->last_token->type = lexer->saved_type;
lexer->last_token->keyword = lexer->saved_keyword;
}
lexer->saved_tokens.release ();
ggc_free (lexer);
}
/* This needs to be set to TRUE before the lexer-debugging infrastructure can
be used. The point of this flag is to help the compiler to fold away calls
to cp_lexer_debugging_p within this source file at compile time, when the
lexer is not being debugged. */
#define LEXER_DEBUGGING_ENABLED_P false
/* Returns nonzero if debugging information should be output. */
static inline bool
cp_lexer_debugging_p (cp_lexer *lexer)
{
if (!LEXER_DEBUGGING_ENABLED_P)
return false;
return lexer->debugging_p;
}
static inline cp_token_position
cp_lexer_token_position (cp_lexer *lexer, bool previous_p)
{
return lexer->next_token - previous_p;
}
static inline cp_token *
cp_lexer_token_at (cp_lexer * /*lexer*/, cp_token_position pos)
{
return pos;
}
static inline void
cp_lexer_set_token_position (cp_lexer *lexer, cp_token_position pos)
{
lexer->next_token = cp_lexer_token_at (lexer, pos);
}
static inline cp_token_position
cp_lexer_previous_token_position (cp_lexer *lexer)
{
return cp_lexer_token_position (lexer, true);
}
static inline cp_token *
cp_lexer_previous_token (cp_lexer *lexer)
{
cp_token_position tp = cp_lexer_previous_token_position (lexer);
/* Skip past purged tokens. */
while (tp->purged_p)
{
gcc_assert (tp != vec_safe_address (lexer->buffer));
tp--;
}
return cp_lexer_token_at (lexer, tp);
}
/* Same as above, but return NULL when the lexer doesn't own the token
buffer or if the next_token is at the start of the token
vector or if all previous tokens are purged. */
static cp_token *
cp_lexer_safe_previous_token (cp_lexer *lexer)
{
if (lexer->buffer
&& lexer->next_token != lexer->buffer->address ())
{
cp_token_position tp = cp_lexer_previous_token_position (lexer);
/* Skip past purged tokens. */
while (tp->purged_p)
{
if (tp == lexer->buffer->address ())
return NULL;
tp--;
}
return cp_lexer_token_at (lexer, tp);
}
return NULL;
}
/* Overload for make_location, taking the lexer to mean the location of the
previous token. */
static inline location_t
make_location (location_t caret, location_t start, cp_lexer *lexer)
{
cp_token *t = cp_lexer_previous_token (lexer);
return make_location (caret, start, t->location);
}
/* Overload for make_location taking tokens instead of locations. */
static inline location_t
make_location (cp_token *caret, cp_token *start, cp_token *end)
{
return make_location (caret->location, start->location, end->location);
}
/* nonzero if we are presently saving tokens. */
static inline int
cp_lexer_saving_tokens (const cp_lexer* lexer)
{
return lexer->saved_tokens.length () != 0;
}
/* Store the next token from the preprocessor in *TOKEN. Return true
if we reach EOF. If LEXER is NULL, assume we are handling an
initial #pragma pch_preprocess, and thus want the lexer to return
processed strings. */
static void
cp_lexer_get_preprocessor_token (unsigned flags, cp_token *token)
{
static int is_extern_c = 0;
/* Get a new token from the preprocessor. */
token->type
= c_lex_with_flags (&token->u.value, &token->location, &token->flags,
flags);
token->keyword = RID_MAX;
token->purged_p = false;
token->error_reported = false;
token->tree_check_p = false;
/* Usually never see a zero, but just in case ... */
token->main_source_p = line_table->depth <= 1;
/* On some systems, some header files are surrounded by an
implicit extern "C" block. Set a flag in the token if it
comes from such a header. */
is_extern_c += pending_lang_change;
pending_lang_change = 0;
token->implicit_extern_c = is_extern_c > 0;
/* Check to see if this token is a keyword. */
if (token->type == CPP_NAME)
{
if (IDENTIFIER_KEYWORD_P (token->u.value))
{
/* Mark this token as a keyword. */
token->type = CPP_KEYWORD;
/* Record which keyword. */
token->keyword = C_RID_CODE (token->u.value);
}
else
{
if (warn_cxx11_compat
&& C_RID_CODE (token->u.value) >= RID_FIRST_CXX11
&& C_RID_CODE (token->u.value) <= RID_LAST_CXX11)
{
/* Warn about the C++0x keyword (but still treat it as
an identifier). */
warning_at (token->location, OPT_Wc__11_compat,
"identifier %qE is a keyword in C++11",
token->u.value);
/* Clear out the C_RID_CODE so we don't warn about this
particular identifier-turned-keyword again. */
C_SET_RID_CODE (token->u.value, RID_MAX);
}
if (warn_cxx20_compat
&& C_RID_CODE (token->u.value) >= RID_FIRST_CXX20
&& C_RID_CODE (token->u.value) <= RID_LAST_CXX20)
{
/* Warn about the C++20 keyword (but still treat it as
an identifier). */
warning_at (token->location, OPT_Wc__20_compat,
"identifier %qE is a keyword in C++20",
token->u.value);
/* Clear out the C_RID_CODE so we don't warn about this
particular identifier-turned-keyword again. */
C_SET_RID_CODE (token->u.value, RID_MAX);
}
token->keyword = RID_MAX;
}
}
else if (token->type == CPP_AT_NAME)
{
/* This only happens in Objective-C++; it must be a keyword. */
token->type = CPP_KEYWORD;
switch (C_RID_CODE (token->u.value))
{
/* Replace 'class' with '@class', 'private' with '@private',
etc. This prevents confusion with the C++ keyword
'class', and makes the tokens consistent with other
Objective-C 'AT' keywords. For example '@class' is
reported as RID_AT_CLASS which is consistent with
'@synchronized', which is reported as
RID_AT_SYNCHRONIZED.
*/
case RID_CLASS: token->keyword = RID_AT_CLASS; break;
case RID_PRIVATE: token->keyword = RID_AT_PRIVATE; break;
case RID_PROTECTED: token->keyword = RID_AT_PROTECTED; break;
case RID_PUBLIC: token->keyword = RID_AT_PUBLIC; break;
case RID_THROW: token->keyword = RID_AT_THROW; break;
case RID_TRY: token->keyword = RID_AT_TRY; break;
case RID_CATCH: token->keyword = RID_AT_CATCH; break;
case RID_SYNCHRONIZED: token->keyword = RID_AT_SYNCHRONIZED; break;
default: token->keyword = C_RID_CODE (token->u.value);
}
}
}
/* Update the globals input_location and the input file stack from TOKEN. */
static inline void
cp_lexer_set_source_position_from_token (cp_token *token)
{
input_location = token->location;
}
/* Update the globals input_location and the input file stack from LEXER. */
static inline void
cp_lexer_set_source_position (cp_lexer *lexer)
{
cp_token *token = cp_lexer_peek_token (lexer);
cp_lexer_set_source_position_from_token (token);
}
/* Return a pointer to the next token in the token stream, but do not
consume it. */
static inline cp_token *
cp_lexer_peek_token (cp_lexer *lexer)
{
if (cp_lexer_debugging_p (lexer))
{
fputs ("cp_lexer: peeking at token: ", cp_lexer_debug_stream);
cp_lexer_print_token (cp_lexer_debug_stream, lexer->next_token);
putc ('\n', cp_lexer_debug_stream);
}
return lexer->next_token;
}
/* Return true if the next token has the indicated TYPE. */
static inline bool
cp_lexer_next_token_is (cp_lexer* lexer, enum cpp_ttype type)
{
return cp_lexer_peek_token (lexer)->type == type;
}
/* Return true if the next token does not have the indicated TYPE. */
static inline bool
cp_lexer_next_token_is_not (cp_lexer* lexer, enum cpp_ttype type)
{
return !cp_lexer_next_token_is (lexer, type);
}
/* Return true if the next token is the indicated KEYWORD. */
static inline bool
cp_lexer_next_token_is_keyword (cp_lexer* lexer, enum rid keyword)
{
return cp_lexer_peek_token (lexer)->keyword == keyword;
}
static inline bool
cp_lexer_nth_token_is (cp_lexer* lexer, size_t n, enum cpp_ttype type)
{
return cp_lexer_peek_nth_token (lexer, n)->type == type;
}
static inline bool
cp_lexer_nth_token_is_keyword (cp_lexer* lexer, size_t n, enum rid keyword)
{
return cp_lexer_peek_nth_token (lexer, n)->keyword == keyword;
}
/* Return true if KEYWORD can start a decl-specifier. */
bool
cp_keyword_starts_decl_specifier_p (enum rid keyword)
{
switch (keyword)
{
/* auto specifier: storage-class-specifier in C++,
simple-type-specifier in C++0x. */
case RID_AUTO:
/* Storage classes. */
case RID_REGISTER:
case RID_STATIC:
case RID_EXTERN:
case RID_MUTABLE:
case RID_THREAD:
/* Elaborated type specifiers. */
case RID_ENUM:
case RID_CLASS:
case RID_STRUCT:
case RID_UNION:
case RID_TYPENAME:
/* Simple type specifiers. */
case RID_CHAR:
case RID_CHAR8:
case RID_CHAR16:
case RID_CHAR32:
case RID_WCHAR:
case RID_BOOL:
case RID_SHORT:
case RID_INT:
case RID_LONG:
case RID_SIGNED:
case RID_UNSIGNED:
case RID_FLOAT:
case RID_DOUBLE:
case RID_VOID:
/* CV qualifiers. */
case RID_CONST:
case RID_VOLATILE:
/* Function specifiers. */
case RID_EXPLICIT:
case RID_VIRTUAL:
/* friend/typdef/inline specifiers. */
case RID_FRIEND:
case RID_TYPEDEF:
case RID_INLINE:
/* GNU extensions. */
case RID_TYPEOF:
/* C++11 extensions. */
case RID_DECLTYPE:
case RID_UNDERLYING_TYPE:
case RID_CONSTEXPR:
/* C++20 extensions. */
case RID_CONSTINIT:
case RID_CONSTEVAL:
return true;
default:
if (keyword >= RID_FIRST_INT_N
&& keyword < RID_FIRST_INT_N + NUM_INT_N_ENTS
&& int_n_enabled_p[keyword - RID_FIRST_INT_N])
return true;
return false;
}
}
/* Return true if the next token is a keyword for a decl-specifier. */
static bool
cp_lexer_next_token_is_decl_specifier_keyword (cp_lexer *lexer)
{
cp_token *token;
token = cp_lexer_peek_token (lexer);
return cp_keyword_starts_decl_specifier_p (token->keyword);
}
/* Returns TRUE iff the token T begins a decltype type. */
static bool
token_is_decltype (cp_token *t)
{
return (t->keyword == RID_DECLTYPE
|| t->type == CPP_DECLTYPE);
}
/* Returns TRUE iff the next token begins a decltype type. */
static bool
cp_lexer_next_token_is_decltype (cp_lexer *lexer)
{
cp_token *t = cp_lexer_peek_token (lexer);
return token_is_decltype (t);
}
/* Called when processing a token with tree_check_value; perform or defer the
associated checks and return the value. */
static tree
saved_checks_value (struct tree_check *check_value)
{
/* Perform any access checks that were deferred. */
vec<deferred_access_check, va_gc> *checks;
deferred_access_check *chk;
checks = check_value->checks;
if (checks)
{
int i;
FOR_EACH_VEC_SAFE_ELT (checks, i, chk)
perform_or_defer_access_check (chk->binfo,
chk->decl,
chk->diag_decl, tf_warning_or_error);
}
/* Return the stored value. */
return check_value->value;
}
/* Return a pointer to the Nth token in the token stream. If N is 1,
then this is precisely equivalent to cp_lexer_peek_token (except
that it is not inline). One would like to disallow that case, but
there is one case (cp_parser_nth_token_starts_template_id) where
the caller passes a variable for N and it might be 1. */
static cp_token *
cp_lexer_peek_nth_token (cp_lexer* lexer, size_t n)
{
cp_token *token;
/* N is 1-based, not zero-based. */
gcc_assert (n > 0);
if (cp_lexer_debugging_p (lexer))
fprintf (cp_lexer_debug_stream,
"cp_lexer: peeking ahead %ld at token: ", (long)n);
--n;
token = lexer->next_token;
while (n && token->type != CPP_EOF)
{
++token;
if (!token->purged_p)
--n;
}
if (cp_lexer_debugging_p (lexer))
{
cp_lexer_print_token (cp_lexer_debug_stream, token);
putc ('\n', cp_lexer_debug_stream);
}
return token;
}
/* Return the next token, and advance the lexer's next_token pointer
to point to the next non-purged token. */
static cp_token *
cp_lexer_consume_token (cp_lexer* lexer)
{
cp_token *token = lexer->next_token;
do
{
gcc_assert (token->type != CPP_EOF);
lexer->next_token++;
}
while (lexer->next_token->purged_p);
cp_lexer_set_source_position_from_token (token);
/* Provide debugging output. */
if (cp_lexer_debugging_p (lexer))
{
fputs ("cp_lexer: consuming token: ", cp_lexer_debug_stream);
cp_lexer_print_token (cp_lexer_debug_stream, token);
putc ('\n', cp_lexer_debug_stream);
}
return token;
}
/* Permanently remove the next token from the token stream, and
advance the next_token pointer to refer to the next non-purged
token. */
static void
cp_lexer_purge_token (cp_lexer *lexer)
{
cp_token *tok = lexer->next_token;
gcc_assert (tok->type != CPP_EOF);
tok->purged_p = true;
tok->location = UNKNOWN_LOCATION;
tok->u.value = NULL_TREE;
tok->keyword = RID_MAX;
do
tok++;
while (tok->purged_p);
lexer->next_token = tok;
}
/* Permanently remove all tokens after TOK, up to, but not
including, the token that will be returned next by
cp_lexer_peek_token. */
static void
cp_lexer_purge_tokens_after (cp_lexer *lexer, cp_token *tok)
{
cp_token *peek = lexer->next_token;
gcc_assert (tok < peek);
for (tok++; tok != peek; tok++)
{
tok->purged_p = true;
tok->location = UNKNOWN_LOCATION;
tok->u.value = NULL_TREE;
tok->keyword = RID_MAX;
}
}
/* Begin saving tokens. All tokens consumed after this point will be
preserved. */
static void
cp_lexer_save_tokens (cp_lexer* lexer)
{
/* Provide debugging output. */
if (cp_lexer_debugging_p (lexer))
fprintf (cp_lexer_debug_stream, "cp_lexer: saving tokens\n");
lexer->saved_tokens.safe_push (lexer->next_token);
}
/* Commit to the portion of the token stream most recently saved. */
static void
cp_lexer_commit_tokens (cp_lexer* lexer)
{
/* Provide debugging output. */
if (cp_lexer_debugging_p (lexer))
fprintf (cp_lexer_debug_stream, "cp_lexer: committing tokens\n");
lexer->saved_tokens.pop ();
}
/* Return all tokens saved since the last call to cp_lexer_save_tokens
to the token stream. Stop saving tokens. */
static void
cp_lexer_rollback_tokens (cp_lexer* lexer)
{
/* Provide debugging output. */
if (cp_lexer_debugging_p (lexer))
fprintf (cp_lexer_debug_stream, "cp_lexer: restoring tokens\n");
lexer->next_token = lexer->saved_tokens.pop ();
}
/* Determines what saved_token_sentinel does when going out of scope. */
enum saved_token_sentinel_mode {
STS_COMMIT,
STS_ROLLBACK,
STS_DONOTHING
};
/* RAII wrapper around the above functions, with sanity checking (the token
stream should be the same at the point of instantiation as it is at the
point of destruction).
Creating a variable saves tokens. MODE determines what happens when the
object is destroyed. STS_COMMIT commits tokens (default),
STS_ROLLBACK rolls-back and STS_DONOTHING does nothing. Calling
rollback() will immediately roll-back tokens and set MODE to
STS_DONOTHING. */
struct saved_token_sentinel
{
cp_lexer *lexer;
unsigned len;
saved_token_sentinel_mode mode;
saved_token_sentinel (cp_lexer *_lexer,
saved_token_sentinel_mode _mode = STS_COMMIT)
: lexer (_lexer), mode (_mode)
{
len = lexer->saved_tokens.length ();
cp_lexer_save_tokens (lexer);
}
void rollback ()
{
cp_lexer_rollback_tokens (lexer);
cp_lexer_set_source_position_from_token
(cp_lexer_previous_token (lexer));
mode = STS_DONOTHING;
}
~saved_token_sentinel ()
{
if (mode == STS_COMMIT)
cp_lexer_commit_tokens (lexer);
else if (mode == STS_ROLLBACK)
rollback ();
gcc_assert (lexer->saved_tokens.length () == len);
}
};
/* Print a representation of the TOKEN on the STREAM. */
static void
cp_lexer_print_token (FILE * stream, cp_token *token)
{
/* We don't use cpp_type2name here because the parser defines
a few tokens of its own. */
static const char *const token_names[] = {
/* cpplib-defined token types */
#define OP(e, s) #e,
#define TK(e, s) #e,
TTYPE_TABLE
#undef OP
#undef TK
/* C++ parser token types - see "Manifest constants", above. */
"KEYWORD",
"TEMPLATE_ID",
"NESTED_NAME_SPECIFIER",
};
/* For some tokens, print the associated data. */
switch (token->type)
{
case CPP_KEYWORD:
/* Some keywords have a value that is not an IDENTIFIER_NODE.
For example, `struct' is mapped to an INTEGER_CST. */
if (!identifier_p (token->u.value))
break;
/* fall through */
case CPP_NAME:
fputs (IDENTIFIER_POINTER (token->u.value), stream);
break;
case CPP_STRING:
case CPP_STRING16:
case CPP_STRING32:
case CPP_WSTRING:
case CPP_UTF8STRING:
fprintf (stream, " \"%s\"", TREE_STRING_POINTER (token->u.value));
break;
case CPP_NUMBER:
print_generic_expr (stream, token->u.value);
break;
default:
/* If we have a name for the token, print it out. Otherwise, we
simply give the numeric code. */
if (token->type < ARRAY_SIZE(token_names))
fputs (token_names[token->type], stream);
else
fprintf (stream, "[%d]", token->type);
break;
}
}
DEBUG_FUNCTION void
debug (cp_token &ref)
{
cp_lexer_print_token (stderr, &ref);
fprintf (stderr, "\n");
}
DEBUG_FUNCTION void
debug (cp_token *ptr)
{
if (ptr)
debug (*ptr);
else
fprintf (stderr, "<nil>\n");
}
/* Start emitting debugging information. */
static void
cp_lexer_start_debugging (cp_lexer* lexer)
{
if (!LEXER_DEBUGGING_ENABLED_P)
fatal_error (input_location,
"%<LEXER_DEBUGGING_ENABLED_P%> is not set to true");
lexer->debugging_p = true;
cp_lexer_debug_stream = stderr;
}
/* Stop emitting debugging information. */
static void
cp_lexer_stop_debugging (cp_lexer* lexer)
{
if (!LEXER_DEBUGGING_ENABLED_P)
fatal_error (input_location,
"%<LEXER_DEBUGGING_ENABLED_P%> is not set to true");
lexer->debugging_p = false;
cp_lexer_debug_stream = NULL;
}
/* Create a new cp_token_cache, representing a range of tokens. */
static cp_token_cache *
cp_token_cache_new (cp_token *first, cp_token *last)
{
cp_token_cache *cache = ggc_alloc<cp_token_cache> ();
cache->first = first;
cache->last = last;
return cache;
}
/* Diagnose if #pragma omp declare simd isn't followed immediately
by function declaration or definition. */
static inline void
cp_ensure_no_omp_declare_simd (cp_parser *parser)
{
if (parser->omp_declare_simd && !parser->omp_declare_simd->error_seen)
{
error ("%<#pragma omp declare %s%> not immediately followed by "
"function declaration or definition",
parser->omp_declare_simd->variant_p ? "variant" : "simd");
parser->omp_declare_simd = NULL;
}
}
/* Finalize #pragma omp declare simd clauses after FNDECL has been parsed,
and put that into "omp declare simd" attribute. */
static inline void
cp_finalize_omp_declare_simd (cp_parser *parser, tree fndecl)
{
if (__builtin_expect (parser->omp_declare_simd != NULL, 0))
{
if (fndecl == error_mark_node)
{
parser->omp_declare_simd = NULL;
return;
}
if (TREE_CODE (fndecl) != FUNCTION_DECL)
{
cp_ensure_no_omp_declare_simd (parser);
return;
}
}
}
/* Similarly, but for use in declaration parsing functions
which call cp_parser_handle_directive_omp_attributes. */
static inline void
cp_finalize_omp_declare_simd (cp_parser *parser, cp_omp_declare_simd_data *data)
{
if (parser->omp_declare_simd != data)
return;
if (!parser->omp_declare_simd->error_seen
&& !parser->omp_declare_simd->fndecl_seen)
error_at (parser->omp_declare_simd->loc,
"%<declare %s%> directive not immediately followed by "
"function declaration or definition",
parser->omp_declare_simd->variant_p ? "variant" : "simd");
parser->omp_declare_simd = NULL;
}
/* Diagnose if #pragma acc routine isn't followed immediately by function
declaration or definition. */
static inline void
cp_ensure_no_oacc_routine (cp_parser *parser)
{
if (parser->oacc_routine && !parser->oacc_routine->error_seen)
{
error_at (parser->oacc_routine->loc,
"%<#pragma acc routine%> not immediately followed by "
"function declaration or definition");
parser->oacc_routine = NULL;
}
}
/* Decl-specifiers. */
/* Set *DECL_SPECS to represent an empty decl-specifier-seq. */
static void
clear_decl_specs (cp_decl_specifier_seq *decl_specs)
{
memset (decl_specs, 0, sizeof (cp_decl_specifier_seq));
}
/* Declarators. */
/* Nothing other than the parser should be creating declarators;
declarators are a semi-syntactic representation of C++ entities.
Other parts of the front end that need to create entities (like
VAR_DECLs or FUNCTION_DECLs) should do that directly. */
static cp_declarator *make_call_declarator
(cp_declarator *, tree, cp_cv_quals, cp_virt_specifiers, cp_ref_qualifier,
tree, tree, tree, tree, location_t);
static cp_declarator *make_array_declarator
(cp_declarator *, tree);
static cp_declarator *make_pointer_declarator
(cp_cv_quals, cp_declarator *, tree);
static cp_declarator *make_reference_declarator
(cp_cv_quals, cp_declarator *, bool, tree);
static cp_declarator *make_ptrmem_declarator
(cp_cv_quals, tree, cp_declarator *, tree);
/* An erroneous declarator. */
static cp_declarator *cp_error_declarator;
/* The obstack on which declarators and related data structures are
allocated. */
static struct obstack declarator_obstack;
/* Alloc BYTES from the declarator memory pool. */
static inline void *
alloc_declarator (size_t bytes)
{
return obstack_alloc (&declarator_obstack, bytes);
}
/* Allocate a declarator of the indicated KIND. Clear fields that are
common to all declarators. */
static cp_declarator *
make_declarator (cp_declarator_kind kind)
{
cp_declarator *declarator;
declarator = (cp_declarator *) alloc_declarator (sizeof (cp_declarator));
declarator->kind = kind;
declarator->parenthesized = UNKNOWN_LOCATION;
declarator->attributes = NULL_TREE;
declarator->std_attributes = NULL_TREE;
declarator->declarator = NULL;
declarator->parameter_pack_p = false;
declarator->id_loc = UNKNOWN_LOCATION;
declarator->init_loc = UNKNOWN_LOCATION;
return declarator;
}
/* Make a declarator for a generalized identifier. If
QUALIFYING_SCOPE is non-NULL, the identifier is
QUALIFYING_SCOPE::UNQUALIFIED_NAME; otherwise, it is just
UNQUALIFIED_NAME. SFK indicates the kind of special function this
is, if any. */
static cp_declarator *
make_id_declarator (tree qualifying_scope, tree unqualified_name,
special_function_kind sfk, location_t id_location)
{
cp_declarator *declarator;
/* It is valid to write:
class C { void f(); };
typedef C D;
void D::f();
The standard is not clear about whether `typedef const C D' is
legal; as of 2002-09-15 the committee is considering that
question. EDG 3.0 allows that syntax. Therefore, we do as
well. */
if (qualifying_scope && TYPE_P (qualifying_scope))
qualifying_scope = TYPE_MAIN_VARIANT (qualifying_scope);
gcc_assert (identifier_p (unqualified_name)
|| TREE_CODE (unqualified_name) == BIT_NOT_EXPR
|| TREE_CODE (unqualified_name) == TEMPLATE_ID_EXPR);
declarator = make_declarator (cdk_id);
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;
}
/* Make a declarator for a pointer to TARGET. CV_QUALIFIERS is a list
of modifiers such as const or volatile to apply to the pointer
type, represented as identifiers. ATTRIBUTES represent the attributes that
appertain to the pointer or reference. */
cp_declarator *
make_pointer_declarator (cp_cv_quals cv_qualifiers, cp_declarator *target,
tree attributes)
{
cp_declarator *declarator;
declarator = make_declarator (cdk_pointer);
declarator->declarator = target;
declarator->u.pointer.qualifiers = cv_qualifiers;
declarator->u.pointer.class_type = NULL_TREE;
if (target)
{
declarator->id_loc = target->id_loc;
declarator->parameter_pack_p = target->parameter_pack_p;
target->parameter_pack_p = false;
}
else
declarator->parameter_pack_p = false;
declarator->std_attributes = attributes;
return declarator;
}
/* Like make_pointer_declarator -- but for references. ATTRIBUTES
represent the attributes that appertain to the pointer or
reference. */
cp_declarator *
make_reference_declarator (cp_cv_quals cv_qualifiers, cp_declarator *target,
bool rvalue_ref, tree attributes)
{
cp_declarator *declarator;
declarator = make_declarator (cdk_reference);
declarator->declarator = target;
declarator->u.reference.qualifiers = cv_qualifiers;
declarator->u.reference.rvalue_ref = rvalue_ref;
if (target)
{
declarator->id_loc = target->id_loc;
declarator->parameter_pack_p = target->parameter_pack_p;
target->parameter_pack_p = false;
}
else
declarator->parameter_pack_p = false;
declarator->std_attributes = attributes;
return declarator;
}
/* Like make_pointer_declarator -- but for a pointer to a non-static
member of CLASS_TYPE. ATTRIBUTES represent the attributes that
appertain to the pointer or reference. */
cp_declarator *
make_ptrmem_declarator (cp_cv_quals cv_qualifiers, tree class_type,
cp_declarator *pointee,
tree attributes)
{
cp_declarator *declarator;
declarator = make_declarator (cdk_ptrmem);
declarator->declarator = pointee;
declarator->u.pointer.qualifiers = cv_qualifiers;
declarator->u.pointer.class_type = class_type;
if (pointee)
{
declarator->parameter_pack_p = pointee->parameter_pack_p;
pointee->parameter_pack_p = false;
}
else
declarator->parameter_pack_p = false;
declarator->std_attributes = attributes;
return declarator;
}
/* Make a declarator for the function given by TARGET, with the
indicated PARMS. The CV_QUALIFIERS apply to the function, as in
"const"-qualified member function. The EXCEPTION_SPECIFICATION
indicates what exceptions can be thrown. */
cp_declarator *
make_call_declarator (cp_declarator *target,
tree parms,
cp_cv_quals cv_qualifiers,
cp_virt_specifiers virt_specifiers,
cp_ref_qualifier ref_qualifier,
tree tx_qualifier,
tree exception_specification,
tree late_return_type,
tree requires_clause,
location_t parens_loc)
{
cp_declarator *declarator;
declarator = make_declarator (cdk_function);
declarator->declarator = target;
declarator->u.function.parameters = parms;
declarator->u.function.qualifiers = cv_qualifiers;
declarator->u.function.virt_specifiers = virt_specifiers;
declarator->u.function.ref_qualifier = ref_qualifier;
declarator->u.function.tx_qualifier = tx_qualifier;
declarator->u.function.exception_specification = exception_specification;
declarator->u.function.late_return_type = late_return_type;
declarator->u.function.requires_clause = requires_clause;
declarator->u.function.parens_loc = parens_loc;
if (target)
{
declarator->id_loc = target->id_loc;
declarator->parameter_pack_p = target->parameter_pack_p;
target->parameter_pack_p = false;
}
else
declarator->parameter_pack_p = false;
return declarator;
}
/* Make a declarator for an array of BOUNDS elements, each of which is
defined by ELEMENT. */
cp_declarator *
make_array_declarator (cp_declarator *element, tree bounds)
{
cp_declarator *declarator;
declarator = make_declarator (cdk_array);
declarator->declarator = element;
declarator->u.array.bounds = bounds;
if (element)
{
declarator->id_loc = element->id_loc;
declarator->parameter_pack_p = element->parameter_pack_p;
element->parameter_pack_p = false;
}
else
declarator->parameter_pack_p = false;
return declarator;
}
/* Determine whether the declarator we've seen so far can be a
parameter pack, when followed by an ellipsis. */
static bool
declarator_can_be_parameter_pack (cp_declarator *declarator)
{
if (declarator && declarator->parameter_pack_p)
/* We already saw an ellipsis. */
return false;
/* 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 cannot be
made into a parameter pack. */
bool found = false;
while (declarator && !found)
{
switch ((int)declarator->kind)
{
case cdk_id:
case cdk_array:
case cdk_decomp:
found = true;
break;
case cdk_error:
return true;
default:
declarator = declarator->declarator;
break;
}
}
return !found;
}
cp_parameter_declarator *no_parameters;
/* Create a parameter declarator with the indicated DECL_SPECIFIERS,
DECLARATOR and DEFAULT_ARGUMENT. */
cp_parameter_declarator *
make_parameter_declarator (cp_decl_specifier_seq *decl_specifiers,
cp_declarator *declarator,
tree default_argument,
location_t loc,
bool template_parameter_pack_p = false)
{
cp_parameter_declarator *parameter;
parameter = ((cp_parameter_declarator *)
alloc_declarator (sizeof (cp_parameter_declarator)));
parameter->next = NULL;
if (decl_specifiers)
parameter->decl_specifiers = *decl_specifiers;
else
clear_decl_specs (&parameter->decl_specifiers);
parameter->declarator = declarator;
parameter->default_argument = default_argument;
parameter->template_parameter_pack_p = template_parameter_pack_p;
parameter->loc = loc;
return parameter;
}
/* Returns true iff DECLARATOR is a declaration for a function. */
static bool
function_declarator_p (const cp_declarator *declarator)
{
while (declarator)
{
if (declarator->kind == cdk_function
&& declarator->declarator->kind == cdk_id)
return true;
if (declarator->kind == cdk_id
|| declarator->kind == cdk_decomp
|| declarator->kind == cdk_error)
return false;
declarator = declarator->declarator;
}
return false;
}
/* The parser. */
/* Overview
--------
A cp_parser parses the token stream as specified by the C++
grammar. Its job is purely parsing, not semantic analysis. For
example, the parser breaks the token stream into declarators,
expressions, statements, and other similar syntactic constructs.
It does not check that the types of the expressions on either side
of an assignment-statement are compatible, or that a function is
not declared with a parameter of type `void'.
The parser invokes routines elsewhere in the compiler to perform
semantic analysis and to build up the abstract syntax tree for the
code processed.
The parser (and the template instantiation code, which is, in a
way, a close relative of parsing) are the only parts of the
compiler that should be calling push_scope and pop_scope, or
related functions. The parser (and template instantiation code)
keeps track of what scope is presently active; everything else
should simply honor that. (The code that generates static
initializers may also need to set the scope, in order to check
access control correctly when emitting the initializers.)
Methodology
-----------
The parser is of the standard recursive-descent variety. Upcoming
tokens in the token stream are examined in order to determine which
production to use when parsing a non-terminal. Some C++ constructs
require arbitrary look ahead to disambiguate. For example, it is
impossible, in the general case, to tell whether a statement is an
expression or declaration without scanning the entire statement.
Therefore, the parser is capable of "parsing tentatively." When the
parser is not sure what construct comes next, it enters this mode.
Then, while we attempt to parse the construct, the parser queues up
error messages, rather than issuing them immediately, and saves the
tokens it consumes. If the construct is parsed successfully, the
parser "commits", i.e., it issues any queued error messages and
the tokens that were being preserved are permanently discarded.
If, however, the construct is not parsed successfully, the parser
rolls back its state completely so that it can resume parsing using
a different alternative.
Future Improvements
-------------------
The performance of the parser could probably be improved substantially.
We could often eliminate the need to parse tentatively by looking ahead
a little bit. In some places, this approach might not entirely eliminate
the need to parse tentatively, but it might still speed up the average
case. */
/* Flags that are passed to some parsing functions. These values can
be bitwise-ored together. */
enum
{
/* No flags. */
CP_PARSER_FLAGS_NONE = 0x0,
/* The construct is optional. If it is not present, then no error
should be issued. */
CP_PARSER_FLAGS_OPTIONAL = 0x1,
/* When parsing a type-specifier, treat user-defined type-names
as non-type identifiers. */
CP_PARSER_FLAGS_NO_USER_DEFINED_TYPES = 0x2,
/* When parsing a type-specifier, do not try to parse a class-specifier
or enum-specifier. */
CP_PARSER_FLAGS_NO_TYPE_DEFINITIONS = 0x4,
/* When parsing a decl-specifier-seq, only allow type-specifier or
constexpr. */
CP_PARSER_FLAGS_ONLY_TYPE_OR_CONSTEXPR = 0x8,
/* When parsing a decl-specifier-seq, only allow mutable, constexpr or
for C++20 consteval. */
CP_PARSER_FLAGS_ONLY_MUTABLE_OR_CONSTEXPR = 0x10,
/* When parsing a decl-specifier-seq, allow missing typename. */
CP_PARSER_FLAGS_TYPENAME_OPTIONAL = 0x20,
/* When parsing of the noexcept-specifier should be delayed. */
CP_PARSER_FLAGS_DELAY_NOEXCEPT = 0x40,
/* When parsing a consteval declarator. */
CP_PARSER_FLAGS_CONSTEVAL = 0x80
};
/* This type is used for parameters and variables which hold
combinations of the above flags. */
typedef int cp_parser_flags;
/* The different kinds of declarators we want to parse. */
enum cp_parser_declarator_kind
{
/* We want an abstract declarator. */
CP_PARSER_DECLARATOR_ABSTRACT,
/* We want a named declarator. */
CP_PARSER_DECLARATOR_NAMED,
/* We don't mind, but the name must be an unqualified-id. */
CP_PARSER_DECLARATOR_EITHER
};
/* The precedence values used to parse binary expressions. The minimum value
of PREC must be 1, because zero is reserved to quickly discriminate
binary operators from other tokens. */
enum cp_parser_prec
{
PREC_NOT_OPERATOR,
PREC_LOGICAL_OR_EXPRESSION,
PREC_LOGICAL_AND_EXPRESSION,
PREC_INCLUSIVE_OR_EXPRESSION,
PREC_EXCLUSIVE_OR_EXPRESSION,
PREC_AND_EXPRESSION,
PREC_EQUALITY_EXPRESSION,
PREC_RELATIONAL_EXPRESSION,
PREC_SPACESHIP_EXPRESSION,
PREC_SHIFT_EXPRESSION,
PREC_ADDITIVE_EXPRESSION,
PREC_MULTIPLICATIVE_EXPRESSION,
PREC_PM_EXPRESSION,
NUM_PREC_VALUES = PREC_PM_EXPRESSION
};
/* A mapping from a token type to a corresponding tree node type, with a
precedence value. */
struct cp_parser_binary_operations_map_node
{
/* The token type. */
enum cpp_ttype token_type;
/* The corresponding tree code. */
enum tree_code tree_type;
/* The precedence of this operator. */
enum cp_parser_prec prec;
};
struct cp_parser_expression_stack_entry
{
/* Left hand side of the binary operation we are currently
parsing. */
cp_expr lhs;
/* Original tree code for left hand side, if it was a binary
expression itself (used for -Wparentheses). */
enum tree_code lhs_type;
/* Tree code for the binary operation we are parsing. */
enum tree_code tree_type;
/* Precedence of the binary operation we are parsing. */
enum cp_parser_prec prec;
/* Location of the binary operation we are parsing. */
location_t loc;
};
/* The stack for storing partial expressions. We only need NUM_PREC_VALUES
entries because precedence levels on the stack are monotonically
increasing. */
typedef struct cp_parser_expression_stack_entry
cp_parser_expression_stack[NUM_PREC_VALUES];
/* Prototypes. */
/* Constructors and destructors. */
static cp_parser_context *cp_parser_context_new
(cp_parser_context *);
/* Class variables. */
static GTY((deletable)) cp_parser_context* cp_parser_context_free_list;
/* The operator-precedence table used by cp_parser_binary_expression.
Transformed into an associative array (binops_by_token) by
cp_parser_new. */
static const cp_parser_binary_operations_map_node binops[] = {
{ CPP_DEREF_STAR, MEMBER_REF, PREC_PM_EXPRESSION },
{ CPP_DOT_STAR, DOTSTAR_EXPR, PREC_PM_EXPRESSION },
{ CPP_MULT, MULT_EXPR, PREC_MULTIPLICATIVE_EXPRESSION },
{ CPP_DIV, TRUNC_DIV_EXPR, PREC_MULTIPLICATIVE_EXPRESSION },
{ CPP_MOD, TRUNC_MOD_EXPR, PREC_MULTIPLICATIVE_EXPRESSION },
{ CPP_PLUS, PLUS_EXPR, PREC_ADDITIVE_EXPRESSION },
{ CPP_MINUS, MINUS_EXPR, PREC_ADDITIVE_EXPRESSION },
{ CPP_LSHIFT, LSHIFT_EXPR, PREC_SHIFT_EXPRESSION },
{ CPP_RSHIFT, RSHIFT_EXPR, PREC_SHIFT_EXPRESSION },
{ CPP_SPACESHIP, SPACESHIP_EXPR, PREC_SPACESHIP_EXPRESSION },
{ CPP_LESS, LT_EXPR, PREC_RELATIONAL_EXPRESSION },
{ CPP_GREATER, GT_EXPR, PREC_RELATIONAL_EXPRESSION },
{ CPP_LESS_EQ, LE_EXPR, PREC_RELATIONAL_EXPRESSION },
{ CPP_GREATER_EQ, GE_EXPR, PREC_RELATIONAL_EXPRESSION },
{ CPP_EQ_EQ, EQ_EXPR, PREC_EQUALITY_EXPRESSION },
{ CPP_NOT_EQ, NE_EXPR, PREC_EQUALITY_EXPRESSION },
{ CPP_AND, BIT_AND_EXPR, PREC_AND_EXPRESSION },
{ CPP_XOR, BIT_XOR_EXPR, PREC_EXCLUSIVE_OR_EXPRESSION },
{ CPP_OR, BIT_IOR_EXPR, PREC_INCLUSIVE_OR_EXPRESSION },
{ CPP_AND_AND, TRUTH_ANDIF_EXPR, PREC_LOGICAL_AND_EXPRESSION },
{ CPP_OR_OR, TRUTH_ORIF_EXPR, PREC_LOGICAL_OR_EXPRESSION }
};
/* The same as binops, but initialized by cp_parser_new so that
binops_by_token[N].token_type == N. Used in cp_parser_binary_expression
for speed. */
static cp_parser_binary_operations_map_node binops_by_token[N_CP_TTYPES];
/* Constructors and destructors. */
/* Construct a new context. The context below this one on the stack
is given by NEXT. */
static cp_parser_context *
cp_parser_context_new (cp_parser_context* next)
{
cp_parser_context *context;
/* Allocate the storage. */
if (cp_parser_context_free_list != NULL)
{
/* Pull the first entry from the free list. */
context = cp_parser_context_free_list;
cp_parser_context_free_list = context->next;
memset (context, 0, sizeof (*context));
}
else
context = ggc_cleared_alloc<cp_parser_context> ();
/* No errors have occurred yet in this context. */
context->status = CP_PARSER_STATUS_KIND_NO_ERROR;
/* If this is not the bottommost context, copy information that we
need from the previous context. */
if (next)
{
/* If, in the NEXT context, we are parsing an `x->' or `x.'
expression, then we are parsing one in this context, too. */
context->object_type = next->object_type;
/* Thread the stack. */
context->next = next;
}
return context;
}
/* Managing the unparsed function queues. */
#define unparsed_funs_with_default_args \
parser->unparsed_queues->last ().funs_with_default_args
#define unparsed_funs_with_definitions \
parser->unparsed_queues->last ().funs_with_definitions
#define unparsed_nsdmis \
parser->unparsed_queues->last ().nsdmis
#define unparsed_noexcepts \
parser->unparsed_queues->last ().noexcepts
static void
push_unparsed_function_queues (cp_parser *parser)
{
cp_unparsed_functions_entry e = { NULL, make_tree_vector (), NULL, NULL };
vec_safe_push (parser->unparsed_queues, e);
}
static void
pop_unparsed_function_queues (cp_parser *parser)
{
release_tree_vector (unparsed_funs_with_definitions);
parser->unparsed_queues->pop ();
}
/* Prototypes. */
/* Constructors and destructors. */
static cp_parser *cp_parser_new
(cp_lexer *);
/* Routines to parse various constructs.
Those that return `tree' will return the error_mark_node (rather
than NULL_TREE) if a parse error occurs, unless otherwise noted.
Sometimes, they will return an ordinary node if error-recovery was
attempted, even though a parse error occurred. So, to check
whether or not a parse error occurred, you should always use
cp_parser_error_occurred. If the construct is optional (indicated
either by an `_opt' in the name of the function that does the
parsing or via a FLAGS parameter), then NULL_TREE is returned if
the construct is not present. */
/* Lexical conventions [gram.lex] */
static cp_expr cp_parser_identifier
(cp_parser *);
static cp_expr cp_parser_string_literal
(cp_parser *, bool, bool, bool);
static cp_expr cp_parser_userdef_char_literal
(cp_parser *);
static tree cp_parser_userdef_string_literal
(tree);
static cp_expr cp_parser_userdef_numeric_literal
(cp_parser *);
/* Basic concepts [gram.basic] */
static void cp_parser_translation_unit (cp_parser *);
/* Expressions [gram.expr] */
static cp_expr cp_parser_primary_expression
(cp_parser *, bool, bool, bool, cp_id_kind *);
static cp_expr cp_parser_id_expression
(cp_parser *, bool, bool, bool *, bool, bool);
static cp_expr cp_parser_unqualified_id
(cp_parser *, bool, bool, bool, bool);
static tree cp_parser_nested_name_specifier_opt
(cp_parser *, bool, bool, bool, bool, bool = false);
static tree cp_parser_nested_name_specifier
(cp_parser *, bool, bool, bool, bool);
static tree cp_parser_qualifying_entity
(cp_parser *, bool, bool, bool, bool, bool);
static cp_expr cp_parser_postfix_expression
(cp_parser *, bool, bool, bool, bool, cp_id_kind *);
static tree cp_parser_postfix_open_square_expression
(cp_parser *, tree, bool, bool);
static tree cp_parser_postfix_dot_deref_expression
(cp_parser *, enum cpp_ttype, cp_expr, bool, cp_id_kind *, location_t);
static vec<tree, va_gc> *cp_parser_parenthesized_expression_list
(cp_parser *, int, bool, bool, bool *, location_t * = NULL,
bool = false);
/* Values for the second parameter of cp_parser_parenthesized_expression_list. */
enum { non_attr = 0, normal_attr = 1, id_attr = 2 };
static void cp_parser_pseudo_destructor_name
(cp_parser *, tree, tree *, tree *);
static cp_expr cp_parser_unary_expression
(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
(cp_parser *);
static tree cp_parser_new_type_id
(cp_parser *, tree *);
static cp_declarator *cp_parser_new_declarator_opt
(cp_parser *);
static cp_declarator *cp_parser_direct_new_declarator
(cp_parser *);
static vec<tree, va_gc> *cp_parser_new_initializer
(cp_parser *);
static tree cp_parser_delete_expression
(cp_parser *);
static cp_expr cp_parser_cast_expression
(cp_parser *, bool, bool, bool, cp_id_kind *);
static cp_expr cp_parser_binary_expression
(cp_parser *, bool, bool, enum cp_parser_prec, cp_id_kind *);
static tree cp_parser_question_colon_clause
(cp_parser *, cp_expr);
static cp_expr cp_parser_assignment_expression
(cp_parser *, cp_id_kind * = NULL, bool = false, bool = false);
static enum tree_code cp_parser_assignment_operator_opt
(cp_parser *);
static cp_expr cp_parser_expression
(cp_parser *, cp_id_kind * = NULL, bool = false, bool = false, bool = false);
static cp_expr cp_parser_constant_expression
(cp_parser *, int = 0, bool * = NULL, bool = false);
static cp_expr cp_parser_builtin_offsetof
(cp_parser *);
static cp_expr cp_parser_lambda_expression
(cp_parser *);
static void cp_parser_lambda_introducer
(cp_parser *, tree);
static bool cp_parser_lambda_declarator_opt
(cp_parser *, tree);
static void cp_parser_lambda_body
(cp_parser *, tree);
/* Statements [gram.stmt.stmt] */
static void cp_parser_statement
(cp_parser *, tree, bool, bool *, vec<tree> * = NULL, location_t * = NULL);
static void cp_parser_label_for_labeled_statement
(cp_parser *, tree);
static tree cp_parser_expression_statement
(cp_parser *, tree);
static tree cp_parser_compound_statement
(cp_parser *, tree, int, bool);
static void cp_parser_statement_seq_opt
(cp_parser *, tree);
static tree cp_parser_selection_statement
(cp_parser *, bool *, vec<tree> *);
static tree cp_parser_condition
(cp_parser *);
static tree cp_parser_iteration_statement
(cp_parser *, bool *, bool, unsigned short);
static bool cp_parser_init_statement
(cp_parser *, tree *decl);
static tree cp_parser_for
(cp_parser *, bool, unsigned short);
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, bool);
static void do_range_for_auto_deduction
(tree, tree);
static tree cp_parser_perform_range_for_lookup
(tree, tree *, tree *);
static tree cp_parser_range_for_member_function
(tree, tree);
static tree cp_parser_jump_statement
(cp_parser *);
static void cp_parser_declaration_statement
(cp_parser *);
static tree cp_parser_implicitly_scoped_statement
(cp_parser *, bool *, const token_indent_info &, vec<tree> * = NULL);
static void cp_parser_already_scoped_statement
(cp_parser *, bool *, const token_indent_info &);
/* State of module-declaration parsing. */
enum module_parse
{
MP_NOT_MODULE, /* Not a module. */
_MP_UNUSED,
MP_FIRST, /* First declaration of TU. */
MP_GLOBAL, /* Global Module Fragment. */
MP_PURVIEW_IMPORTS, /* Imports of a module. */
MP_PURVIEW, /* Purview of a named module. */
MP_PRIVATE_IMPORTS, /* Imports of a Private Module Fragment. */
MP_PRIVATE, /* Private Module Fragment. */
};
static module_parse cp_parser_module_declaration
(cp_parser *parser, module_parse, bool exporting);
static void cp_parser_import_declaration
(cp_parser *parser, module_parse, bool exporting);
/* Declarations [gram.dcl.dcl] */
static void cp_parser_declaration_seq_opt
(cp_parser *);
static void cp_parser_declaration
(cp_parser *, tree);
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 *, bool, tree *);
static void cp_parser_decl_specifier_seq
(cp_parser *, cp_parser_flags, cp_decl_specifier_seq *, int *);
static tree cp_parser_storage_class_specifier_opt
(cp_parser *);
static tree cp_parser_function_specifier_opt
(cp_parser *, cp_decl_specifier_seq *);
static tree cp_parser_type_specifier
(cp_parser *, cp_parser_flags, cp_decl_specifier_seq *, bool,
int *, bool *);
static tree cp_parser_simple_type_specifier
(cp_parser *, cp_decl_specifier_seq *, cp_parser_flags);
static tree cp_parser_placeholder_type_specifier
(cp_parser *, location_t, tree, bool);
static tree cp_parser_type_name
(cp_parser *, bool);
static tree cp_parser_nonclass_name
(cp_parser* parser);
static tree cp_parser_elaborated_type_specifier
(cp_parser *, bool, bool);
static tree cp_parser_enum_specifier
(cp_parser *);
static void cp_parser_enumerator_list
(cp_parser *, tree);
static void cp_parser_enumerator_definition
(cp_parser *, tree);
static tree cp_parser_namespace_name
(cp_parser *);
static void cp_parser_namespace_definition
(cp_parser *);
static void cp_parser_namespace_body
(cp_parser *);
static tree cp_parser_qualified_namespace_specifier
(cp_parser *);
static void cp_parser_namespace_alias_definition
(cp_parser *);
static bool cp_parser_using_declaration
(cp_parser *, bool);
static void cp_parser_using_directive
(cp_parser *);
static void cp_parser_using_enum
(cp_parser *);
static tree cp_parser_alias_declaration
(cp_parser *);
static void cp_parser_asm_definition
(cp_parser *);
static void cp_parser_linkage_specification
(cp_parser *, tree);
static void cp_parser_static_assert
(cp_parser *, bool);
static tree cp_parser_decltype
(cp_parser *);
static tree cp_parser_decomposition_declaration
(cp_parser *, cp_decl_specifier_seq *, tree *, location_t *);
/* Declarators [gram.dcl.decl] */
static tree cp_parser_init_declarator
(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, cp_parser_flags, int *, bool *,
bool, bool, bool);
static cp_declarator *cp_parser_direct_declarator
(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
(cp_parser *);
static cp_virt_specifiers cp_parser_virt_specifier_seq_opt
(cp_parser *);
static cp_ref_qualifier cp_parser_ref_qualifier_opt
(cp_parser *);
static tree cp_parser_tx_qualifier_opt
(cp_parser *);
static tree cp_parser_late_return_type_opt
(cp_parser *, cp_declarator *, tree &);
static tree cp_parser_declarator_id
(cp_parser *, bool);
static tree cp_parser_type_id
(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 *, cp_parser_flags, bool, bool, location_t *);
static void cp_parser_type_specifier_seq
(cp_parser *, cp_parser_flags, bool, bool, cp_decl_specifier_seq *);
static tree cp_parser_parameter_declaration_clause
(cp_parser *, cp_parser_flags);
static tree cp_parser_parameter_declaration_list
(cp_parser *, cp_parser_flags);
static cp_parameter_declarator *cp_parser_parameter_declaration
(cp_parser *, cp_parser_flags, bool, bool *);
static tree cp_parser_default_argument
(cp_parser *, bool);
static void cp_parser_function_body
(cp_parser *, bool);
static tree cp_parser_initializer
(cp_parser *, bool *, bool *, bool = false);
static cp_expr cp_parser_initializer_clause
(cp_parser *, bool *);
static cp_expr cp_parser_braced_list
(cp_parser*, bool*);
static vec<constructor_elt, va_gc> *cp_parser_initializer_list
(cp_parser *, bool *, bool *);
static void cp_parser_ctor_initializer_opt_and_function_body
(cp_parser *, bool);
static tree cp_parser_late_parsing_omp_declare_simd
(cp_parser *, tree);
static tree cp_parser_late_parsing_oacc_routine
(cp_parser *, tree);
static tree synthesize_implicit_template_parm
(cp_parser *, tree);
static tree finish_fully_implicit_template
(cp_parser *, tree);
static void abort_fully_implicit_template
(cp_parser *);
/* Classes [gram.class] */
static tree cp_parser_class_name
(cp_parser *, bool, bool, enum tag_types, bool, bool, bool, bool = false);
static tree cp_parser_class_specifier
(cp_parser *);
static tree cp_parser_class_head
(cp_parser *, bool *);
static enum tag_types cp_parser_class_key
(cp_parser *);
static void cp_parser_type_parameter_key
(cp_parser* parser);
static void cp_parser_member_specification_opt
(cp_parser *);
static void cp_parser_member_declaration
(cp_parser *);
static tree cp_parser_pure_specifier
(cp_parser *);
static tree cp_parser_constant_initializer
(cp_parser *);
/* Derived classes [gram.class.derived] */
static tree cp_parser_base_clause
(cp_parser *);
static tree cp_parser_base_specifier
(cp_parser *);
/* Special member functions [gram.special] */
static tree cp_parser_conversion_function_id
(cp_parser *);
static tree cp_parser_conversion_type_id
(cp_parser *);
static cp_declarator *cp_parser_conversion_declarator_opt
(cp_parser *);
static void cp_parser_ctor_initializer_opt
(cp_parser *);
static void cp_parser_mem_initializer_list
(cp_parser *);
static tree cp_parser_mem_initializer
(cp_parser *);
static tree cp_parser_mem_initializer_id
(cp_parser *);
/* Overloading [gram.over] */
static cp_expr cp_parser_operator_function_id
(cp_parser *);
static cp_expr cp_parser_operator
(cp_parser *, location_t);
/* Templates [gram.temp] */
static void cp_parser_template_declaration
(cp_parser *, bool);
static tree cp_parser_template_parameter_list
(cp_parser *);
static tree cp_parser_template_parameter
(cp_parser *, bool *, bool *);
static tree cp_parser_type_parameter
(cp_parser *, bool *);
static tree cp_parser_template_id
(cp_parser *, bool, bool, enum tag_types, bool);
static tree cp_parser_template_id_expr
(cp_parser *, bool, bool, bool);
static tree cp_parser_template_name
(cp_parser *, bool, bool, bool, enum tag_types, bool *);
static tree cp_parser_template_argument_list
(cp_parser *);
static tree cp_parser_template_argument
(cp_parser *);
static void cp_parser_explicit_instantiation
(cp_parser *);
static void cp_parser_explicit_specialization
(cp_parser *);
/* Exception handling [gram.except] */
static tree cp_parser_try_block
(cp_parser *);
static void cp_parser_function_try_block
(cp_parser *);
static void cp_parser_handler_seq
(cp_parser *);
static void cp_parser_handler
(cp_parser *);
static tree cp_parser_exception_declaration
(cp_parser *);
static tree cp_parser_throw_expression
(cp_parser *);
static tree cp_parser_exception_specification_opt
(cp_parser *, cp_parser_flags);
static tree cp_parser_type_id_list
(cp_parser *);
static tree cp_parser_noexcept_specification_opt
(cp_parser *, cp_parser_flags, bool, bool *, bool);
/* GNU Extensions */
static tree cp_parser_asm_specification_opt
(cp_parser *);
static tree cp_parser_asm_operand_list
(cp_parser *);
static tree cp_parser_asm_clobber_list
(cp_parser *);
static tree cp_parser_asm_label_list
(cp_parser *);
static bool cp_next_tokens_can_be_attribute_p
(cp_parser *);
static bool cp_next_tokens_can_be_gnu_attribute_p
(cp_parser *);
static bool cp_next_tokens_can_be_std_attribute_p
(cp_parser *);
static bool cp_nth_tokens_can_be_std_attribute_p
(cp_parser *, size_t);
static bool cp_nth_tokens_can_be_gnu_attribute_p
(cp_parser *, size_t);
static bool cp_nth_tokens_can_be_attribute_p
(cp_parser *, size_t);
static tree cp_parser_attributes_opt
(cp_parser *);
static tree cp_parser_gnu_attributes_opt
(cp_parser *);
static tree cp_parser_gnu_attribute_list
(cp_parser *, bool = false);
static tree cp_parser_std_attribute
(cp_parser *, tree);
static tree cp_parser_std_attribute_spec
(cp_parser *);
static tree cp_parser_std_attribute_spec_seq
(cp_parser *);
static size_t cp_parser_skip_std_attribute_spec_seq
(cp_parser *, size_t);
static size_t cp_parser_skip_attributes_opt
(cp_parser *, size_t);
static bool cp_parser_extension_opt
(cp_parser *, int *);
static void cp_parser_label_declaration
(cp_parser *);
/* Concept Extensions */
static tree cp_parser_concept_definition
(cp_parser *);
static tree cp_parser_constraint_expression
(cp_parser *);
static tree cp_parser_requires_clause_opt
(cp_parser *, bool);
static tree cp_parser_requires_expression
(cp_parser *);
static tree cp_parser_requirement_parameter_list
(cp_parser *);
static tree cp_parser_requirement_body
(cp_parser *);
static tree cp_parser_requirement_seq
(cp_parser *);
static tree cp_parser_requirement
(cp_parser *);
static tree cp_parser_simple_requirement
(cp_parser *);
static tree cp_parser_compound_requirement
(cp_parser *);
static tree cp_parser_type_requirement
(cp_parser *);
static tree cp_parser_nested_requirement
(cp_parser *);
/* Transactional Memory Extensions */
static tree cp_parser_transaction
(cp_parser *, cp_token *);
static tree cp_parser_transaction_expression
(cp_parser *, enum rid);
static void cp_parser_function_transaction
(cp_parser *, enum rid);
static tree cp_parser_transaction_cancel
(cp_parser *);
/* Coroutine extensions. */
static tree cp_parser_yield_expression
(cp_parser *);
enum pragma_context {
pragma_external,
pragma_member,
pragma_objc_icode,
pragma_stmt,
pragma_compound
};
static bool cp_parser_pragma
(cp_parser *, enum pragma_context, bool *);
/* Objective-C++ Productions */
static tree cp_parser_objc_message_receiver
(cp_parser *);
static tree cp_parser_objc_message_args
(cp_parser *);
static tree cp_parser_objc_message_expression
(cp_parser *);
static cp_expr cp_parser_objc_encode_expression
(cp_parser *);
static tree cp_parser_objc_defs_expression
(cp_parser *);
static tree cp_parser_objc_protocol_expression
(cp_parser *);
static tree cp_parser_objc_selector_expression
(cp_parser *);
static cp_expr cp_parser_objc_expression
(cp_parser *);
static bool cp_parser_objc_selector_p
(enum cpp_ttype);
static tree cp_parser_objc_selector
(cp_parser *);
static tree cp_parser_objc_protocol_refs_opt
(cp_parser *);
static void cp_parser_objc_declaration
(cp_parser *, tree);
static tree cp_parser_objc_statement
(cp_parser *);
static bool cp_parser_objc_valid_prefix_attributes
(cp_parser *, tree *);
static void cp_parser_objc_at_property_declaration
(cp_parser *) ;
static void cp_parser_objc_at_synthesize_declaration
(cp_parser *) ;
static void cp_parser_objc_at_dynamic_declaration
(cp_parser *) ;
static tree cp_parser_objc_struct_declaration
(cp_parser *) ;
/* Utility Routines */
static cp_expr cp_parser_lookup_name
(cp_parser *, tree, enum tag_types, bool, bool, bool, tree *, location_t);
static tree cp_parser_lookup_name_simple
(cp_parser *, tree, location_t);
static tree cp_parser_maybe_treat_template_as_class
(tree, bool);
static bool cp_parser_check_declarator_template_parameters
(cp_parser *, cp_declarator *, location_t);
static bool cp_parser_check_template_parameters
(cp_parser *, unsigned, bool, location_t, cp_declarator *);
static cp_expr cp_parser_simple_cast_expression
(cp_parser *);
static tree cp_parser_global_scope_opt
(cp_parser *, bool);
static bool cp_parser_constructor_declarator_p
(cp_parser *, cp_parser_flags, bool);
static tree cp_parser_function_definition_from_specifiers_and_declarator
(cp_parser *, cp_decl_specifier_seq *, tree, const cp_declarator *);
static tree cp_parser_function_definition_after_declarator
(cp_parser *, bool);
static bool cp_parser_template_declaration_after_export
(cp_parser *, bool);
static void cp_parser_perform_template_parameter_access_checks
(vec<deferred_access_check, va_gc> *);
static tree cp_parser_single_declaration
(cp_parser *, vec<deferred_access_check, va_gc> *, bool, bool, bool *);
static cp_expr cp_parser_functional_cast
(cp_parser *, tree);
static tree cp_parser_save_member_function_body
(cp_parser *, cp_decl_specifier_seq *, cp_declarator *, tree);
static tree cp_parser_save_nsdmi
(cp_parser *);
static tree cp_parser_enclosed_template_argument_list
(cp_parser *);
static void cp_parser_save_default_args
(cp_parser *, tree);
static void cp_parser_late_parsing_for_member
(cp_parser *, tree);
static tree cp_parser_late_parse_one_default_arg
(cp_parser *, tree, tree, tree);
static void cp_parser_late_parsing_nsdmi
(cp_parser *, tree);
static void cp_parser_late_parsing_default_args
(cp_parser *, tree);
static tree cp_parser_sizeof_operand
(cp_parser *, enum rid);
static cp_expr cp_parser_trait_expr
(cp_parser *, enum rid);
static bool cp_parser_declares_only_class_p
(cp_parser *);
static void cp_parser_set_storage_class
(cp_parser *, cp_decl_specifier_seq *, enum rid, cp_token *);
static void cp_parser_set_decl_spec_type
(cp_decl_specifier_seq *, tree, cp_token *, bool);
static void set_and_check_decl_spec_loc
(cp_decl_specifier_seq *decl_specs,
cp_decl_spec ds, cp_token *);
static bool cp_parser_friend_p
(const cp_decl_specifier_seq *);
static void cp_parser_required_error
(cp_parser *, required_token, bool, location_t);
static cp_token *cp_parser_require
(cp_parser *, enum cpp_ttype, required_token, location_t = UNKNOWN_LOCATION);
static cp_token *cp_parser_require_keyword
(cp_parser *, enum rid, required_token);
static bool cp_parser_token_starts_function_definition_p
(cp_token *);
static bool cp_parser_next_token_starts_class_definition_p
(cp_parser *);
static bool cp_parser_next_token_ends_template_argument_p
(cp_parser *);
static bool cp_parser_nth_token_starts_template_argument_list_p
(cp_parser *, size_t);
static enum tag_types cp_parser_token_is_class_key
(cp_token *);
static enum tag_types cp_parser_token_is_type_parameter_key
(cp_token *);
static void cp_parser_maybe_warn_enum_key (cp_parser *, location_t, tree, rid);
static void cp_parser_check_class_key
(cp_parser *, location_t, enum tag_types, tree type, bool, bool);
static void cp_parser_check_access_in_redeclaration
(tree type, location_t location);
static bool cp_parser_optional_template_keyword
(cp_parser *);
static void cp_parser_pre_parsed_nested_name_specifier
(cp_parser *);
static bool cp_parser_cache_group
(cp_parser *, enum cpp_ttype, unsigned);
static tree cp_parser_cache_defarg
(cp_parser *parser, bool nsdmi);
static void cp_parser_parse_tentatively
(cp_parser *);
static void cp_parser_commit_to_tentative_parse
(cp_parser *);
static void cp_parser_commit_to_topmost_tentative_parse
(cp_parser *);
static void cp_parser_abort_tentative_parse
(cp_parser *);
static bool cp_parser_parse_definitely
(cp_parser *);
static inline bool cp_parser_parsing_tentatively
(cp_parser *);
static bool cp_parser_uncommitted_to_tentative_parse_p
(cp_parser *);
static void cp_parser_error
(cp_parser *, const char *);
static void cp_parser_name_lookup_error
(cp_parser *, tree, tree, name_lookup_error, location_t);
static bool cp_parser_simulate_error
(cp_parser *);
static bool cp_parser_check_type_definition
(cp_parser *);
static void cp_parser_check_for_definition_in_return_type
(cp_declarator *, tree, location_t type_location);
static void cp_parser_check_for_invalid_template_id
(cp_parser *, tree, enum tag_types, location_t location);
static bool cp_parser_non_integral_constant_expression
(cp_parser *, non_integral_constant);
static void cp_parser_diagnose_invalid_type_name
(cp_parser *, tree, location_t);
static bool cp_parser_parse_and_diagnose_invalid_type_name
(cp_parser *);
static int cp_parser_skip_to_closing_parenthesis
(cp_parser *, bool, bool, bool);
static void cp_parser_skip_to_end_of_statement
(cp_parser *);
static void cp_parser_consume_semicolon_at_end_of_statement
(cp_parser *);
static void cp_parser_skip_to_end_of_block_or_statement
(cp_parser *);
static bool cp_parser_skip_to_closing_brace
(cp_parser *);
static bool cp_parser_skip_entire_template_parameter_list
(cp_parser *);
static void cp_parser_require_end_of_template_parameter_list
(cp_parser *);
static bool cp_parser_skip_to_end_of_template_parameter_list
(cp_parser *);
static void cp_parser_skip_to_pragma_eol
(cp_parser*, cp_token *);
static bool cp_parser_error_occurred
(cp_parser *);
static bool cp_parser_allow_gnu_extensions_p
(cp_parser *);
static bool cp_parser_is_pure_string_literal
(cp_token *);
static bool cp_parser_is_string_literal
(cp_token *);
static bool cp_parser_is_keyword
(cp_token *, enum rid);
static tree cp_parser_make_typename_type
(cp_parser *, tree, location_t location);
static cp_declarator * cp_parser_make_indirect_declarator
(enum tree_code, tree, cp_cv_quals, cp_declarator *, tree);
static bool cp_parser_compound_literal_p
(cp_parser *);
static bool cp_parser_array_designator_p
(cp_parser *);
static bool cp_parser_init_statement_p
(cp_parser *);
static bool cp_parser_skip_to_closing_square_bracket
(cp_parser *);
static size_t cp_parser_skip_balanced_tokens (cp_parser *, size_t);
// -------------------------------------------------------------------------- //
// Unevaluated Operand Guard
//
// Implementation of an RAII helper for unevaluated operand parsing.
cp_unevaluated::cp_unevaluated ()
{
++cp_unevaluated_operand;
++c_inhibit_evaluation_warnings;
}
cp_unevaluated::~cp_unevaluated ()
{
--c_inhibit_evaluation_warnings;
--cp_unevaluated_operand;
}
// -------------------------------------------------------------------------- //
// Tentative Parsing
/* Returns nonzero if we are parsing tentatively. */
static inline bool
cp_parser_parsing_tentatively (cp_parser* parser)
{
return parser->context->next != NULL;
}
/* Returns nonzero if TOKEN is a string literal. */
static bool
cp_parser_is_pure_string_literal (cp_token* token)
{
return (token->type == CPP_STRING ||
token->type == CPP_STRING16 ||
token->type == CPP_STRING32 ||
token->type == CPP_WSTRING ||
token->type == CPP_UTF8STRING);
}
/* Returns nonzero if TOKEN is a string literal
of a user-defined string literal. */
static bool
cp_parser_is_string_literal (cp_token* token)
{
return (cp_parser_is_pure_string_literal (token) ||
token->type == CPP_STRING_USERDEF ||
token->type == CPP_STRING16_USERDEF ||
token->type == CPP_STRING32_USERDEF ||
token->type == CPP_WSTRING_USERDEF ||
token->type == CPP_UTF8STRING_USERDEF);
}
/* Returns nonzero if TOKEN is the indicated KEYWORD. */
static bool
cp_parser_is_keyword (cp_token* token, enum rid keyword)
{
return token->keyword == keyword;
}
/* Return TOKEN's pragma_kind if it is CPP_PRAGMA, otherwise
PRAGMA_NONE. */
static enum pragma_kind
cp_parser_pragma_kind (cp_token *token)
{
if (token->type != CPP_PRAGMA)
return PRAGMA_NONE;
/* We smuggled the cpp_token->u.pragma value in an INTEGER_CST. */
return (enum pragma_kind) TREE_INT_CST_LOW (token->u.value);
}
/* Helper function for cp_parser_error.
Having peeked a token of kind TOK1_KIND that might signify
a conflict marker, peek successor tokens to determine
if we actually do have a conflict marker.
Specifically, we consider a run of 7 '<', '=' or '>' characters
at the start of a line as a conflict marker.
These come through the lexer as three pairs and a single,
e.g. three CPP_LSHIFT tokens ("<<") and a CPP_LESS token ('<').
If it returns true, *OUT_LOC is written to with the location/range
of the marker. */
static bool
cp_lexer_peek_conflict_marker (cp_lexer *lexer, enum cpp_ttype tok1_kind,
location_t *out_loc)
{
cp_token *token2 = cp_lexer_peek_nth_token (lexer, 2);
if (token2->type != tok1_kind)
return false;
cp_token *token3 = cp_lexer_peek_nth_token (lexer, 3);
if (token3->type != tok1_kind)
return false;
cp_token *token4 = cp_lexer_peek_nth_token (lexer, 4);
if (token4->type != conflict_marker_get_final_tok_kind (tok1_kind))
return false;
/* It must be at the start of the line. */
location_t start_loc = cp_lexer_peek_token (lexer)->location;
if (LOCATION_COLUMN (start_loc) != 1)
return false;
/* We have a conflict marker. Construct a location of the form:
<<<<<<<
^~~~~~~
with start == caret, finishing at the end of the marker. */
location_t finish_loc = get_finish (token4->location);
*out_loc = make_location (start_loc, start_loc, finish_loc);
return true;
}
/* Get a description of the matching symbol to TOKEN_DESC e.g. "(" for
RT_CLOSE_PAREN. */
static const char *
get_matching_symbol (required_token token_desc)
{
switch (token_desc)
{
default:
gcc_unreachable ();
return "";
case RT_CLOSE_BRACE:
return "{";
case RT_CLOSE_PAREN:
return "(";
}
}
/* Attempt to convert TOKEN_DESC from a required_token to an
enum cpp_ttype, returning CPP_EOF if there is no good conversion. */
static enum cpp_ttype
get_required_cpp_ttype (required_token token_desc)
{
switch (token_desc)
{
case RT_SEMICOLON:
return CPP_SEMICOLON;
case RT_OPEN_PAREN:
return CPP_OPEN_PAREN;
case RT_CLOSE_BRACE:
return CPP_CLOSE_BRACE;
case RT_OPEN_BRACE:
return CPP_OPEN_BRACE;
case RT_CLOSE_SQUARE:
return CPP_CLOSE_SQUARE;
case RT_OPEN_SQUARE:
return CPP_OPEN_SQUARE;
case RT_COMMA:
return CPP_COMMA;
case RT_COLON:
return CPP_COLON;
case RT_CLOSE_PAREN:
return CPP_CLOSE_PAREN;
default:
/* Use CPP_EOF as a "no completions possible" code. */
return CPP_EOF;
}
}
/* Subroutine of cp_parser_error and cp_parser_required_error.
Issue a diagnostic of the form
FILE:LINE: MESSAGE before TOKEN
where TOKEN is the next token in the input stream. MESSAGE
(specified by the caller) is usually of the form "expected
OTHER-TOKEN".
This bypasses the check for tentative passing, and potentially
adds material needed by cp_parser_required_error.
If MISSING_TOKEN_DESC is not RT_NONE, then potentially add fix-it hints
suggesting insertion of the missing token.
Additionally, if MATCHING_LOCATION is not UNKNOWN_LOCATION, then we
have an unmatched symbol at MATCHING_LOCATION; highlight this secondary
location. */
static void
cp_parser_error_1 (cp_parser* parser, const char* gmsgid,
required_token missing_token_desc,
location_t matching_location)
{
cp_token *token = cp_lexer_peek_token (parser->lexer);
/* This diagnostic makes more sense if it is tagged to the line
of the token we just peeked at. */
cp_lexer_set_source_position_from_token (token);
if (token->type == CPP_PRAGMA)
{
error_at (token->location,
"%<#pragma%> is not allowed here");
cp_parser_skip_to_pragma_eol (parser, token);
return;
}
/* If this is actually a conflict marker, report it as such. */
if (token->type == CPP_LSHIFT
|| token->type == CPP_RSHIFT
|| token->type == CPP_EQ_EQ)
{
location_t loc;
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. */
for (;;)
{
cp_lexer_consume_token (parser->lexer);
cp_token *next = cp_lexer_peek_token (parser->lexer);
if (next->type == CPP_EOF)
break;
if (next->location == UNKNOWN_LOCATION
|| loc == UNKNOWN_LOCATION)
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;
}
}
auto_diagnostic_group d;
gcc_rich_location richloc (input_location);
bool added_matching_location = false;
if (missing_token_desc != RT_NONE)
if (cp_token *prev_token = cp_lexer_safe_previous_token (parser->lexer))
{
/* Potentially supply a fix-it hint, suggesting to add the
missing token immediately after the *previous* token.
This may move the primary location within richloc. */
enum cpp_ttype ttype = get_required_cpp_ttype (missing_token_desc);
location_t prev_token_loc = prev_token->location;
maybe_suggest_missing_token_insertion (&richloc, ttype,
prev_token_loc);
/* If matching_location != UNKNOWN_LOCATION, highlight it.
Attempt to consolidate diagnostics by printing it as a
secondary range within the main diagnostic. */
if (matching_location != UNKNOWN_LOCATION)
added_matching_location
= richloc.add_location_if_nearby (matching_location);
}
/* If we were parsing a string-literal and there is an unknown name
token right after, then check to see if that could also have been
a literal string by checking the name against a list of known
standard string literal constants defined in header files. If
there is one, then add that as an hint to the error message. */
name_hint h;
if (token->type == CPP_NAME)
if (cp_token *prev_token = cp_lexer_safe_previous_token (parser->lexer))
if (cp_parser_is_string_literal (prev_token))
{
tree name = token->u.value;
const char *token_name = IDENTIFIER_POINTER (name);
const char *header_hint
= get_cp_stdlib_header_for_string_macro_name (token_name);
if (header_hint != NULL)
h = name_hint (NULL, new suggest_missing_header (token->location,
token_name,
header_hint));
}
/* Actually emit the error. */
c_parse_error (gmsgid,
/* Because c_parser_error does not understand
CPP_KEYWORD, keywords are treated like
identifiers. */
(token->type == CPP_KEYWORD ? CPP_NAME : token->type),
token->u.value, token->flags, &richloc);
if (missing_token_desc != RT_NONE)
{
/* If we weren't able to consolidate matching_location, then
print it as a secondary diagnostic. */
if (matching_location != UNKNOWN_LOCATION
&& !added_matching_location)
inform (matching_location, "to match this %qs",
get_matching_symbol (missing_token_desc));
}
}
/* If not parsing tentatively, issue a diagnostic of the form
FILE:LINE: MESSAGE before TOKEN
where TOKEN is the next token in the input stream. MESSAGE
(specified by the caller) is usually of the form "expected
OTHER-TOKEN". */
static void
cp_parser_error (cp_parser* parser, const char* gmsgid)
{
if (!cp_parser_simulate_error (parser))
cp_parser_error_1 (parser, gmsgid, RT_NONE, UNKNOWN_LOCATION);
}
/* Issue an error about name-lookup failing. NAME is the
IDENTIFIER_NODE DECL is the result of
the lookup (as returned from cp_parser_lookup_name). DESIRED is
the thing that we hoped to find. */
static void
cp_parser_name_lookup_error (cp_parser* parser,
tree name,
tree decl,
name_lookup_error desired,
location_t location)
{
/* If name lookup completely failed, tell the user that NAME was not
declared. */
if (decl == error_mark_node)
{
if (parser->scope && parser->scope != global_namespace)
error_at (location, "%<%E::%E%> has not been declared",
parser->scope, name);
else if (parser->scope == global_namespace)
error_at (location, "%<::%E%> has not been declared", name);
else if (parser->object_scope
&& !CLASS_TYPE_P (parser->object_scope))
error_at (location, "request for member %qE in non-class type %qT",
name, parser->object_scope);
else if (parser->object_scope)
error_at (location, "%<%T::%E%> has not been declared",
parser->object_scope, name);
else
error_at (location, "%qE has not been declared", name);
}
else if (parser->scope && parser->scope != global_namespace)
{
switch (desired)
{
case NLE_TYPE:
error_at (location, "%<%E::%E%> is not a type",
parser->scope, name);
break;
case NLE_CXX98:
error_at (location, "%<%E::%E%> is not a class or namespace",
parser->scope, name);
break;
case NLE_NOT_CXX98:
error_at (location,
"%<%E::%E%> is not a class, namespace, or enumeration",
parser->scope, name);
break;
default:
gcc_unreachable ();
}
}
else if (parser->scope == global_namespace)
{
switch (desired)
{
case NLE_TYPE:
error_at (location, "%<::%E%> is not a type", name);
break;
case NLE_CXX98:
error_at (location, "%<::%E%> is not a class or namespace", name);
break;
case NLE_NOT_CXX98:
error_at (location,
"%<::%E%> is not a class, namespace, or enumeration",
name);
break;
default:
gcc_unreachable ();
}
}
else
{
switch (desired)
{
case NLE_TYPE:
error_at (location, "%qE is not a type", name);
break;
case NLE_CXX98:
error_at (location, "%qE is not a class or namespace", name);
break;
case NLE_NOT_CXX98:
error_at (location,
"%qE is not a class, namespace, or enumeration", name);
break;
default:
gcc_unreachable ();
}
}
}
/* If we are parsing tentatively, remember that an error has occurred
during this tentative parse. Returns true if the error was
simulated; false if a message should be issued by the caller. */
static bool
cp_parser_simulate_error (cp_parser* parser)
{
if (cp_parser_uncommitted_to_tentative_parse_p (parser))
{
parser->context->status = CP_PARSER_STATUS_KIND_ERROR;
return true;
}
return false;
}
/* This function is called when a type is defined. If type
definitions are forbidden at this point, an error message is
issued. */
static bool
cp_parser_check_type_definition (cp_parser* parser)
{
/* If types are forbidden here, issue a message. */
if (parser->type_definition_forbidden_message)
{
/* Don't use `%s' to print the string, because quotations (`%<', `%>')
or %qs in the message need to be interpreted. */
error (parser->type_definition_forbidden_message,
parser->type_definition_forbidden_message_arg);
return false;
}
return true;
}
/* This function is called when the DECLARATOR is processed. The TYPE
was a type defined in the decl-specifiers. If it is invalid to
define a type in the decl-specifiers for DECLARATOR, an error is
issued. TYPE_LOCATION is the location of TYPE and is used
for error reporting. */
static void
cp_parser_check_for_definition_in_return_type (cp_declarator *declarator,
tree type, location_t type_location)
{
/* [dcl.fct] forbids type definitions in return types.
Unfortunately, it's not easy to know whether or not we are
processing a return type until after the fact. */
while (declarator
&& (declarator->kind == cdk_pointer
|| declarator->kind == cdk_reference
|| declarator->kind == cdk_ptrmem))
declarator = declarator->declarator;
if (declarator
&& declarator->kind == cdk_function)
{
error_at (type_location,
"new types may not be defined in a return type");
inform (type_location,
"(perhaps a semicolon is missing after the definition of %qT)",
type);
}
}
/* A type-specifier (TYPE) has been parsed which cannot be followed by
"<" in any valid C++ program. If the next token is indeed "<",
issue a message warning the user about what appears to be an
invalid attempt to form a template-id. LOCATION is the location
of the type-specifier (TYPE) */
static void
cp_parser_check_for_invalid_template_id (cp_parser* parser,
tree type,
enum tag_types tag_type,
location_t location)
{
cp_token_position start = 0;
if (cp_lexer_next_token_is (parser->lexer, CPP_LESS))
{
if (TREE_CODE (type) == TYPE_DECL)
type = TREE_TYPE (type);
if (TYPE_P (type) && !template_placeholder_p (type))
error_at (location, "%qT is not a template", type);
else if (identifier_p (type))
{
if (tag_type != none_type)
error_at (location, "%qE is not a class template", type);
else
error_at (location, "%qE is not a template", type);
}
else
error_at (location, "invalid template-id");
/* Remember the location of the invalid "<". */