summaryrefslogtreecommitdiff
path: root/libcpp
diff options
context:
space:
mode:
authorRichard Sandiford <richard.sandiford@linaro.org>2017-11-20 16:02:55 +0000
committerRichard Sandiford <richard.sandiford@linaro.org>2017-11-20 16:02:55 +0000
commitd58952aefb03632bbb5b441d5c0bd330711f0af1 (patch)
treed046e56bfbd6a40106ae6ab96fafc954f1dfc955 /libcpp
parent648f8fc59b2cc39abd24f4c22388b346cdebcc31 (diff)
parent50221fae802a10fafe95e61d40504a58da33e98f (diff)
downloadgcc-linaro-dev/sve.tar.gz
Merge trunk into svelinaro-dev/sve
Diffstat (limited to 'libcpp')
-rw-r--r--libcpp/ChangeLog38
-rw-r--r--libcpp/identifiers.c2
-rw-r--r--libcpp/include/cpplib.h3
-rw-r--r--libcpp/include/line-map.h46
-rw-r--r--libcpp/init.c44
-rw-r--r--libcpp/internal.h3
-rw-r--r--libcpp/lex.c42
-rw-r--r--libcpp/macro.c170
-rw-r--r--libcpp/pch.c1
9 files changed, 297 insertions, 52 deletions
diff --git a/libcpp/ChangeLog b/libcpp/ChangeLog
index 39e12bda927..70c834c61d0 100644
--- a/libcpp/ChangeLog
+++ b/libcpp/ChangeLog
@@ -1,3 +1,41 @@
+2017-11-13 Tom Tromey <tom@tromey.com>
+
+ * pch.c (cpp_read_state): Set n__VA_OPT__.
+ * macro.c (vaopt_state): New class.
+ (_cpp_arguments_ok): Check va_opt flag.
+ (replace_args, create_iso_definition): Use vaopt_state.
+ * lex.c (lex_identifier_intern): Possibly issue errors for
+ __VA_OPT__.
+ (lex_identifier): Likewise.
+ (maybe_va_opt_error): New function.
+ * internal.h (struct lexer_state) <va_args_ok>: Update comment.
+ (struct spec_nodes) <n__VA_OPT__>: New field.
+ * init.c (struct lang_flags) <va_opt>: New field.
+ (lang_defaults): Add entries for C++2A. Update all entries for
+ va_opt.
+ (cpp_set_lang): Initialize va_opt.
+ * include/cpplib.h (struct cpp_options) <va_opt>: New field.
+ * identifiers.c (_cpp_init_hashtable): Initialize n__VA_OPT__.
+
+2017-11-13 David Malcolm <dmalcolm@redhat.com>
+
+ * include/line-map.h (linenum_type): Move this typedef and the
+ comment describing column numbering to near the top of the file.
+
+2017-11-06 Mukesh Kapoor <mukesh.kapoor@oracle.com>
+
+ PR c++/80955
+ * lex.c (lex_string): When checking for a valid macro for the
+ warning related to -Wliteral-suffix (CPP_W_LITERAL_SUFFIX),
+ check that the macro name does not start with an underscore
+ before calling is_macro().
+
+2017-11-05 Tom de Vries <tom@codesourcery.com>
+
+ PR other/82784
+ * lex.c (BUF_APPEND): Remove semicolon after
+ "do {} while (0)".
+
2017-10-31 David Malcolm <dmalcolm@redhat.com>
* directives.c (_cpp_handle_directive): Update for renaming of
diff --git a/libcpp/identifiers.c b/libcpp/identifiers.c
index 220f9b97f0d..e456fd3a4fc 100644
--- a/libcpp/identifiers.c
+++ b/libcpp/identifiers.c
@@ -70,6 +70,8 @@ _cpp_init_hashtable (cpp_reader *pfile, cpp_hash_table *table)
s->n_false = cpp_lookup (pfile, DSC("false"));
s->n__VA_ARGS__ = cpp_lookup (pfile, DSC("__VA_ARGS__"));
s->n__VA_ARGS__->flags |= NODE_DIAGNOSTIC;
+ s->n__VA_OPT__ = cpp_lookup (pfile, DSC("__VA_OPT__"));
+ s->n__VA_OPT__->flags |= NODE_DIAGNOSTIC;
s->n__has_include__ = cpp_lookup (pfile, DSC("__has_include__"));
s->n__has_include_next__ = cpp_lookup (pfile, DSC("__has_include_next__"));
}
diff --git a/libcpp/include/cpplib.h b/libcpp/include/cpplib.h
index 5a14858c44f..101b33aef48 100644
--- a/libcpp/include/cpplib.h
+++ b/libcpp/include/cpplib.h
@@ -478,6 +478,9 @@ struct cpp_options
/* Nonzero for C++ 2014 Standard digit separators. */
unsigned char digit_separators;
+ /* Nonzero for C++2a __VA_OPT__ feature. */
+ unsigned char va_opt;
+
/* Holds the name of the target (execution) character set. */
const char *narrow_charset;
diff --git a/libcpp/include/line-map.h b/libcpp/include/line-map.h
index e6960410c00..8b7e5dcd0ae 100644
--- a/libcpp/include/line-map.h
+++ b/libcpp/include/line-map.h
@@ -26,6 +26,29 @@ along with this program; see the file COPYING3. If not see
#define GTY(x) /* nothing */
#endif
+/* Both gcc and emacs number source *lines* starting at 1, but
+ they have differing conventions for *columns*.
+
+ GCC uses a 1-based convention for source columns,
+ whereas Emacs's M-x column-number-mode uses a 0-based convention.
+
+ For example, an error in the initial, left-hand
+ column of source line 3 is reported by GCC as:
+
+ some-file.c:3:1: error: ...etc...
+
+ On navigating to the location of that error in Emacs
+ (e.g. via "next-error"),
+ the locus is reported in the Mode Line
+ (assuming M-x column-number-mode) as:
+
+ some-file.c 10% (3, 0)
+
+ i.e. "3:1:" in GCC corresponds to "(3, 0)" in Emacs. */
+
+/* The type of line numbers. */
+typedef unsigned int linenum_type;
+
/* Reason for creating a new line map with linemap_add. LC_ENTER is
when including a new file, e.g. a #include directive in C.
LC_LEAVE is when reaching a file's end. LC_RENAME is when a file
@@ -43,9 +66,6 @@ enum lc_reason
/* FIXME: add support for stringize and paste. */
};
-/* The type of line numbers. */
-typedef unsigned int linenum_type;
-
/* The typedef "source_location" is a key within the location database,
identifying a source location or macro expansion, along with range
information, and (optionally) a pointer for use by gcc.
@@ -1251,26 +1271,6 @@ typedef struct
bool sysp;
} expanded_location;
-/* Both gcc and emacs number source *lines* starting at 1, but
- they have differing conventions for *columns*.
-
- GCC uses a 1-based convention for source columns,
- whereas Emacs's M-x column-number-mode uses a 0-based convention.
-
- For example, an error in the initial, left-hand
- column of source line 3 is reported by GCC as:
-
- some-file.c:3:1: error: ...etc...
-
- On navigating to the location of that error in Emacs
- (e.g. via "next-error"),
- the locus is reported in the Mode Line
- (assuming M-x column-number-mode) as:
-
- some-file.c 10% (3, 0)
-
- i.e. "3:1:" in GCC corresponds to "(3, 0)" in Emacs. */
-
/* A location within a rich_location: a caret&range, with
the caret potentially flagged for display. */
diff --git a/libcpp/init.c b/libcpp/init.c
index ecc81e3138a..8423656ad10 100644
--- a/libcpp/init.c
+++ b/libcpp/init.c
@@ -91,30 +91,31 @@ struct lang_flags
char digit_separators;
char trigraphs;
char utf8_char_literals;
+ char va_opt;
};
static const struct lang_flags lang_defaults[] =
-{ /* c99 c++ xnum xid c11 std digr ulit rlit udlit bincst digsep trig u8chlit */
- /* GNUC89 */ { 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0 },
- /* GNUC99 */ { 1, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0 },
- /* GNUC11 */ { 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0 },
- /* GNUC17 */ { 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0 },
- /* STDC89 */ { 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0 },
- /* STDC94 */ { 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0 },
- /* STDC99 */ { 1, 0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0 },
- /* STDC11 */ { 1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0 },
- /* STDC17 */ { 1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0 },
- /* GNUCXX */ { 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0 },
- /* CXX98 */ { 0, 1, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0 },
- /* GNUCXX11 */ { 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0 },
- /* CXX11 */ { 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0 },
- /* GNUCXX14 */ { 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 0 },
- /* CXX14 */ { 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0 },
- /* GNUCXX17 */ { 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1 },
- /* CXX17 */ { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1 },
- /* GNUCXX2A */ { 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1 },
- /* CXX2A */ { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1 },
- /* ASM */ { 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
+{ /* c99 c++ xnum xid c11 std digr ulit rlit udlit bincst digsep trig u8chlit vaopt */
+ /* GNUC89 */ { 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1 },
+ /* GNUC99 */ { 1, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1 },
+ /* GNUC11 */ { 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1 },
+ /* GNUC17 */ { 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1 },
+ /* STDC89 */ { 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0 },
+ /* STDC94 */ { 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0 },
+ /* STDC99 */ { 1, 0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0 },
+ /* STDC11 */ { 1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0 },
+ /* STDC17 */ { 1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0 },
+ /* GNUCXX */ { 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1 },
+ /* CXX98 */ { 0, 1, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0 },
+ /* GNUCXX11 */ { 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1 },
+ /* CXX11 */ { 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0 },
+ /* GNUCXX14 */ { 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 1 },
+ /* CXX14 */ { 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0 },
+ /* GNUCXX17 */ { 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1 },
+ /* CXX17 */ { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0 },
+ /* GNUCXX2A */ { 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1 },
+ /* CXX2A */ { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1 },
+ /* ASM */ { 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
};
/* Sets internal flags correctly for a given language. */
@@ -139,6 +140,7 @@ cpp_set_lang (cpp_reader *pfile, enum c_lang lang)
CPP_OPTION (pfile, digit_separators) = l->digit_separators;
CPP_OPTION (pfile, trigraphs) = l->trigraphs;
CPP_OPTION (pfile, utf8_char_literals) = l->utf8_char_literals;
+ CPP_OPTION (pfile, va_opt) = l->va_opt;
}
/* Initialize library global state. */
diff --git a/libcpp/internal.h b/libcpp/internal.h
index f24e85cfb11..0a33abafd43 100644
--- a/libcpp/internal.h
+++ b/libcpp/internal.h
@@ -246,7 +246,7 @@ struct lexer_state
all directives apart from #define. */
unsigned char save_comments;
- /* Nonzero if lexing __VA_ARGS__ is valid. */
+ /* Nonzero if lexing __VA_ARGS__ and __VA_OPT__ are valid. */
unsigned char va_args_ok;
/* Nonzero if lexing poisoned identifiers is valid. */
@@ -282,6 +282,7 @@ struct spec_nodes
cpp_hashnode *n_true; /* C++ keyword true */
cpp_hashnode *n_false; /* C++ keyword false */
cpp_hashnode *n__VA_ARGS__; /* C99 vararg macros */
+ cpp_hashnode *n__VA_OPT__; /* C++ vararg macros */
cpp_hashnode *n__has_include__; /* __has_include__ operator */
cpp_hashnode *n__has_include_next__; /* __has_include_next__ operator */
};
diff --git a/libcpp/lex.c b/libcpp/lex.c
index 40ff801e8e3..a8dc3bae5e4 100644
--- a/libcpp/lex.c
+++ b/libcpp/lex.c
@@ -1352,6 +1352,28 @@ forms_identifier_p (cpp_reader *pfile, int first,
return false;
}
+/* Helper function to issue error about improper __VA_OPT__ use. */
+static void
+maybe_va_opt_error (cpp_reader *pfile)
+{
+ if (CPP_PEDANTIC (pfile) && !CPP_OPTION (pfile, va_opt))
+ {
+ /* __VA_OPT__ should not be accepted at all, but allow it in
+ system headers. */
+ if (!cpp_in_system_header (pfile))
+ cpp_error (pfile, CPP_DL_PEDWARN,
+ "__VA_OPT__ is not available until C++2a");
+ }
+ else if (!pfile->state.va_args_ok)
+ {
+ /* __VA_OPT__ should only appear in the replacement list of a
+ variadic macro. */
+ cpp_error (pfile, CPP_DL_PEDWARN,
+ "__VA_OPT__ can only appear in the expansion"
+ " of a C++2a variadic macro");
+ }
+}
+
/* Helper function to get the cpp_hashnode of the identifier BASE. */
static cpp_hashnode *
lex_identifier_intern (cpp_reader *pfile, const uchar *base)
@@ -1396,6 +1418,9 @@ lex_identifier_intern (cpp_reader *pfile, const uchar *base)
" of a C99 variadic macro");
}
+ if (result == pfile->spec_nodes.n__VA_OPT__)
+ maybe_va_opt_error (pfile);
+
/* For -Wc++-compat, warn about use of C++ named operators. */
if (result->flags & NODE_WARN_OPERATOR)
cpp_warning (pfile, CPP_W_CXX_OPERATOR_NAMES,
@@ -1485,6 +1510,11 @@ lex_identifier (cpp_reader *pfile, const uchar *base, bool starts_ucn,
" of a C99 variadic macro");
}
+ /* __VA_OPT__ should only appear in the replacement list of a
+ variadic macro. */
+ if (result == pfile->spec_nodes.n__VA_OPT__)
+ maybe_va_opt_error (pfile);
+
/* For -Wc++-compat, warn about use of C++ named operators. */
if (result->flags & NODE_WARN_OPERATOR)
cpp_warning (pfile, CPP_W_CXX_OPERATOR_NAMES,
@@ -1647,7 +1677,7 @@ lex_raw_string (cpp_reader *pfile, cpp_token *token, const uchar *base,
(const uchar *)(STR), (LEN)); \
temp_buffer_len += (LEN); \
} \
- } while (0);
+ } while (0)
orig_base = base;
++cur;
@@ -1871,8 +1901,9 @@ lex_raw_string (cpp_reader *pfile, cpp_token *token, const uchar *base,
/* If a string format macro, say from inttypes.h, is placed touching
a string literal it could be parsed as a C++11 user-defined string
literal thus breaking the program.
- Try to identify macros with is_macro. A warning is issued. */
- if (is_macro (pfile, cur))
+ Try to identify macros with is_macro. A warning is issued.
+ The macro name should not start with '_' for this warning. */
+ if ((*cur != '_') && is_macro (pfile, cur))
{
/* Raise a warning, but do not consume subsequent tokens. */
if (CPP_OPTION (pfile, warn_literal_suffix) && !pfile->state.skipping)
@@ -2001,8 +2032,9 @@ lex_string (cpp_reader *pfile, cpp_token *token, const uchar *base)
/* If a string format macro, say from inttypes.h, is placed touching
a string literal it could be parsed as a C++11 user-defined string
literal thus breaking the program.
- Try to identify macros with is_macro. A warning is issued. */
- if (is_macro (pfile, cur))
+ Try to identify macros with is_macro. A warning is issued.
+ The macro name should not start with '_' for this warning. */
+ if ((*cur != '_') && is_macro (pfile, cur))
{
/* Raise a warning, but do not consume subsequent tokens. */
if (CPP_OPTION (pfile, warn_literal_suffix) && !pfile->state.skipping)
diff --git a/libcpp/macro.c b/libcpp/macro.c
index fab1cb051dc..bf473eae358 100644
--- a/libcpp/macro.c
+++ b/libcpp/macro.c
@@ -89,6 +89,155 @@ struct macro_arg_saved_data {
union _cpp_hashnode_value value;
};
+static const char *vaopt_paste_error =
+ N_("'##' cannot appear at either end of __VA_OPT__");
+
+/* A class for tracking __VA_OPT__ state while iterating over a
+ sequence of tokens. This is used during both macro definition and
+ expansion. */
+class vaopt_state {
+
+ public:
+
+ /* Initialize the state tracker. ANY_ARGS is true if variable
+ arguments were provided to the macro invocation. */
+ vaopt_state (cpp_reader *pfile, bool is_variadic, bool any_args)
+ : m_pfile (pfile),
+ m_allowed (any_args),
+ m_variadic (is_variadic),
+ m_state (0),
+ m_last_was_paste (false),
+ m_paste_location (0),
+ m_location (0)
+ {
+ }
+
+ enum update_type
+ {
+ ERROR,
+ DROP,
+ INCLUDE
+ };
+
+ /* Given a token, update the state of this tracker and return a
+ boolean indicating whether the token should be be included in the
+ expansion. */
+ update_type update (const cpp_token *token)
+ {
+ /* If the macro isn't variadic, just don't bother. */
+ if (!m_variadic)
+ return INCLUDE;
+
+ if (token->type == CPP_NAME
+ && token->val.node.node == m_pfile->spec_nodes.n__VA_OPT__)
+ {
+ if (m_state > 0)
+ {
+ cpp_error_at (m_pfile, CPP_DL_ERROR, token->src_loc,
+ "__VA_OPT__ may not appear in a __VA_OPT__");
+ return ERROR;
+ }
+ ++m_state;
+ m_location = token->src_loc;
+ return DROP;
+ }
+ else if (m_state == 1)
+ {
+ if (token->type != CPP_OPEN_PAREN)
+ {
+ cpp_error_at (m_pfile, CPP_DL_ERROR, m_location,
+ "__VA_OPT__ must be followed by an "
+ "open parenthesis");
+ return ERROR;
+ }
+ ++m_state;
+ return DROP;
+ }
+ else if (m_state >= 2)
+ {
+ if (m_state == 2 && token->type == CPP_PASTE)
+ {
+ cpp_error_at (m_pfile, CPP_DL_ERROR, token->src_loc,
+ vaopt_paste_error);
+ return ERROR;
+ }
+ /* Advance states before further considering this token, in
+ case we see a close paren immediately after the open
+ paren. */
+ if (m_state == 2)
+ ++m_state;
+
+ bool was_paste = m_last_was_paste;
+ m_last_was_paste = false;
+ if (token->type == CPP_PASTE)
+ {
+ m_last_was_paste = true;
+ m_paste_location = token->src_loc;
+ }
+ else if (token->type == CPP_OPEN_PAREN)
+ ++m_state;
+ else if (token->type == CPP_CLOSE_PAREN)
+ {
+ --m_state;
+ if (m_state == 2)
+ {
+ /* Saw the final paren. */
+ m_state = 0;
+
+ if (was_paste)
+ {
+ cpp_error_at (m_pfile, CPP_DL_ERROR, token->src_loc,
+ vaopt_paste_error);
+ return ERROR;
+ }
+
+ return DROP;
+ }
+ }
+ return m_allowed ? INCLUDE : DROP;
+ }
+
+ /* Nothing to do with __VA_OPT__. */
+ return INCLUDE;
+ }
+
+ /* Ensure that any __VA_OPT__ was completed. If ok, return true.
+ Otherwise, issue an error and return false. */
+ bool completed ()
+ {
+ if (m_variadic && m_state != 0)
+ cpp_error_at (m_pfile, CPP_DL_ERROR, m_location,
+ "unterminated __VA_OPT__");
+ return m_state == 0;
+ }
+
+ private:
+
+ /* The cpp_reader. */
+ cpp_reader *m_pfile;
+
+ /* True if there were varargs. */
+ bool m_allowed;
+ /* True if the macro is variadic. */
+ bool m_variadic;
+
+ /* The state variable:
+ 0 means not parsing
+ 1 means __VA_OPT__ seen, looking for "("
+ 2 means "(" seen (so the next token can't be "##")
+ >= 3 means looking for ")", the number encodes the paren depth. */
+ int m_state;
+
+ /* If true, the previous token was ##. This is used to detect when
+ a paste occurs at the end of the sequence. */
+ bool m_last_was_paste;
+ /* The location of the paste token. */
+ source_location m_paste_location;
+
+ /* Location of the __VA_OPT__ token. */
+ source_location m_location;
+};
+
/* Macro expansion. */
static int enter_macro_context (cpp_reader *, cpp_hashnode *,
@@ -776,7 +925,8 @@ _cpp_arguments_ok (cpp_reader *pfile, cpp_macro *macro, const cpp_hashnode *node
if (argc < macro->paramc)
{
- /* As an extension, variadic arguments are allowed to not appear in
+ /* In C++2a (here the va_opt flag is used), and also as a GNU
+ extension, variadic arguments are allowed to not appear in
the invocation at all.
e.g. #define debug(format, args...) something
debug("string");
@@ -786,7 +936,8 @@ _cpp_arguments_ok (cpp_reader *pfile, cpp_macro *macro, const cpp_hashnode *node
if (argc + 1 == macro->paramc && macro->variadic)
{
- if (CPP_PEDANTIC (pfile) && ! macro->syshdr)
+ if (CPP_PEDANTIC (pfile) && ! macro->syshdr
+ && ! CPP_OPTION (pfile, va_opt))
{
if (CPP_OPTION (pfile, cplusplus))
cpp_error (pfile, CPP_DL_PEDWARN,
@@ -1678,6 +1829,8 @@ replace_args (cpp_reader *pfile, cpp_hashnode *node, cpp_macro *macro,
num_macro_tokens);
}
i = 0;
+ vaopt_state vaopt_tracker (pfile, macro->variadic,
+ args[macro->paramc - 1].count > 0);
for (src = macro->exp.tokens; src < limit; src++)
{
unsigned int arg_tokens_count;
@@ -1685,6 +1838,10 @@ replace_args (cpp_reader *pfile, cpp_hashnode *node, cpp_macro *macro,
const cpp_token **paste_flag = NULL;
const cpp_token **tmp_token_ptr;
+ /* __VA_OPT__ handling. */
+ if (vaopt_tracker.update (src) != vaopt_state::INCLUDE)
+ continue;
+
if (src->type != CPP_MACRO_ARG)
{
/* Allocate a virtual location for token SRC, and add that
@@ -3076,6 +3233,9 @@ create_iso_definition (cpp_reader *pfile, cpp_macro *macro)
*token = *ctoken;
}
+ /* The argument doesn't matter here. */
+ vaopt_state vaopt_tracker (pfile, macro->variadic, true);
+
for (;;)
{
/* Check the stringifying # constraint 6.10.3.2.1 of
@@ -3144,10 +3304,16 @@ create_iso_definition (cpp_reader *pfile, cpp_macro *macro)
}
}
+ if (vaopt_tracker.update (token) == vaopt_state::ERROR)
+ return false;
+
following_paste_op = (token->type == CPP_PASTE);
token = lex_expansion_token (pfile, macro);
}
+ if (!vaopt_tracker.completed ())
+ return false;
+
macro->exp.tokens = (cpp_token *) BUFF_FRONT (pfile->a_buff);
macro->traditional = 0;
diff --git a/libcpp/pch.c b/libcpp/pch.c
index cad4b872cda..b685a38a854 100644
--- a/libcpp/pch.c
+++ b/libcpp/pch.c
@@ -835,6 +835,7 @@ cpp_read_state (cpp_reader *r, const char *name, FILE *f,
s->n_true = cpp_lookup (r, DSC("true"));
s->n_false = cpp_lookup (r, DSC("false"));
s->n__VA_ARGS__ = cpp_lookup (r, DSC("__VA_ARGS__"));
+ s->n__VA_OPT__ = cpp_lookup (r, DSC("__VA_OPT__"));
s->n__has_include__ = cpp_lookup (r, DSC("__has_include__"));
s->n__has_include_next__ = cpp_lookup (r, DSC("__has_include_next__"));
}