aboutsummaryrefslogtreecommitdiff
path: root/libcpp/directives.c
diff options
context:
space:
mode:
Diffstat (limited to 'libcpp/directives.c')
-rw-r--r--libcpp/directives.c77
1 files changed, 66 insertions, 11 deletions
diff --git a/libcpp/directives.c b/libcpp/directives.c
index 0d09da7..261a584 100644
--- a/libcpp/directives.c
+++ b/libcpp/directives.c
@@ -1,5 +1,5 @@
/* CPP Library. (Directive handling.)
- Copyright (C) 1986-2020 Free Software Foundation, Inc.
+ Copyright (C) 1986-2021 Free Software Foundation, Inc.
Contributed by Per Bothner, 1994-95.
Based on CCCP program by Paul Rubin, June 1986
Adapted to ANSI C, Richard Stallman, Jan 1987
@@ -56,10 +56,12 @@ struct pragma_entry
/* Values for the origin field of struct directive. KANDR directives
come from traditional (K&R) C. STDC89 directives come from the
- 1989 C standard. EXTENSION directives are extensions. */
+ 1989 C standard. STDC2X directives come from the C2X standard. EXTENSION
+ directives are extensions. */
#define KANDR 0
#define STDC89 1
-#define EXTENSION 2
+#define STDC2X 2
+#define EXTENSION 3
/* Values for the flags field of struct directive. COND indicates a
conditional; IF_COND an opening conditional. INCL means to treat
@@ -67,13 +69,17 @@ struct pragma_entry
means this directive should be handled even if -fpreprocessed is in
effect (these are the directives with callback hooks).
- EXPAND is set on directives that are always macro-expanded. */
+ EXPAND is set on directives that are always macro-expanded.
+
+ ELIFDEF is set on directives that are only handled for standards with the
+ #elifdef / #elifndef feature. */
#define COND (1 << 0)
#define IF_COND (1 << 1)
#define INCL (1 << 2)
#define IN_I (1 << 3)
#define EXPAND (1 << 4)
#define DEPRECATED (1 << 5)
+#define ELIFDEF (1 << 6)
/* Defines one #-directive, including how to handle it. */
typedef void (*directive_handler) (cpp_reader *);
@@ -148,6 +154,8 @@ static void cpp_pop_definition (cpp_reader *, struct def_pragma_macro *);
D(undef, T_UNDEF, KANDR, IN_I) \
D(line, T_LINE, KANDR, EXPAND) \
D(elif, T_ELIF, STDC89, COND | EXPAND) \
+ D(elifdef, T_ELIFDEF, STDC2X, COND | ELIFDEF) \
+ D(elifndef, T_ELIFNDEF, STDC2X, COND | ELIFDEF) \
D(error, T_ERROR, STDC89, 0) \
D(pragma, T_PRAGMA, STDC89, IN_I) \
D(warning, T_WARNING, EXTENSION, 0) \
@@ -437,7 +445,11 @@ _cpp_handle_directive (cpp_reader *pfile, bool indented)
if (dname->type == CPP_NAME)
{
if (dname->val.node.node->is_directive)
- dir = &dtable[dname->val.node.node->directive_index];
+ {
+ dir = &dtable[dname->val.node.node->directive_index];
+ if ((dir->flags & ELIFDEF) && !CPP_OPTION (pfile, elifdef))
+ dir = 0;
+ }
}
/* We do not recognize the # followed by a number extension in
assembler code. */
@@ -922,12 +934,19 @@ strtolinenum (const uchar *str, size_t len, linenum_type *nump, bool *wrapped)
linenum_type reg = 0;
uchar c;
+ bool seen_digit_sep = false;
*wrapped = false;
while (len--)
{
c = *str++;
+ if (!seen_digit_sep && c == '\'' && len)
+ {
+ seen_digit_sep = true;
+ continue;
+ }
if (!ISDIGIT (c))
return true;
+ seen_digit_sep = false;
if (reg > ((linenum_type) -1) / 10)
*wrapped = true;
reg *= 10;
@@ -2072,8 +2091,8 @@ do_else (cpp_reader *pfile)
}
}
-/* Handle a #elif directive by not changing if_stack either. See the
- comment above do_else. */
+/* Handle a #elif, #elifdef or #elifndef directive by not changing if_stack
+ either. See the comment above do_else. */
static void
do_elif (cpp_reader *pfile)
{
@@ -2081,12 +2100,13 @@ do_elif (cpp_reader *pfile)
struct if_stack *ifs = buffer->if_stack;
if (ifs == NULL)
- cpp_error (pfile, CPP_DL_ERROR, "#elif without #if");
+ cpp_error (pfile, CPP_DL_ERROR, "#%s without #if", pfile->directive->name);
else
{
if (ifs->type == T_ELSE)
{
- cpp_error (pfile, CPP_DL_ERROR, "#elif after #else");
+ cpp_error (pfile, CPP_DL_ERROR, "#%s after #else",
+ pfile->directive->name);
cpp_error_with_line (pfile, CPP_DL_ERROR, ifs->line, 0,
"the conditional began here");
}
@@ -2100,8 +2120,29 @@ do_elif (cpp_reader *pfile)
pfile->state.skipping = 1;
else
{
- pfile->state.skipping = ! _cpp_parse_expr (pfile, false);
- ifs->skip_elses = ! pfile->state.skipping;
+ if (pfile->directive == &dtable[T_ELIF])
+ pfile->state.skipping = !_cpp_parse_expr (pfile, false);
+ else
+ {
+ cpp_hashnode *node = lex_macro_node (pfile, false);
+
+ if (node)
+ {
+ bool macro_defined = _cpp_defined_macro_p (node);
+ if (!_cpp_maybe_notify_macro_use (pfile, node,
+ pfile->directive_line))
+ /* It wasn't a macro after all. */
+ macro_defined = false;
+ bool skip = (pfile->directive == &dtable[T_ELIFDEF]
+ ? !macro_defined
+ : macro_defined);
+ if (pfile->cb.used)
+ pfile->cb.used (pfile, pfile->directive_line, node);
+ check_eol (pfile, false);
+ pfile->state.skipping = skip;
+ }
+ }
+ ifs->skip_elses = !pfile->state.skipping;
}
/* Invalidate any controlling macro. */
@@ -2109,6 +2150,20 @@ do_elif (cpp_reader *pfile)
}
}
+/* Handle a #elifdef directive. */
+static void
+do_elifdef (cpp_reader *pfile)
+{
+ do_elif (pfile);
+}
+
+/* Handle a #elifndef directive. */
+static void
+do_elifndef (cpp_reader *pfile)
+{
+ do_elif (pfile);
+}
+
/* #endif pops the if stack and resets pfile->state.skipping. */
static void
do_endif (cpp_reader *pfile)