+2020-01-20 Nathan Sidwell <nathan@acm.org>
+
+ PR preprocessor/80005
+ * c-cppbuiltins.c (c_cpp_builtins): Don't define __has_include{,_next}.
+
2020-01-18 Iain Sandoe <iain@sandoe.co.uk>
* c-common.c (co_await, co_yield, co_return): New.
/* For stddef.h. They require macros defined in c-common.c. */
c_stddef_cpp_builtins ();
- /* Set include test macros for all C/C++ (not for just C++11 etc.)
- The builtins __has_include__ and __has_include_next__ are defined
- in libcpp. */
- cpp_define (pfile, "__has_include(STR)=__has_include__(STR)");
- cpp_define (pfile, "__has_include_next(STR)=__has_include_next__(STR)");
-
if (c_dialect_cxx ())
{
if (flag_weak && SUPPORTS_ONE_ONLY)
+2020-01-20 Nathan Sidwell <nathan@acm.org>
+
+ PR preprocessor/80005
+ * g++.dg/cpp1y/feat-cxx14.C: Adjust.
+ * g++.dg/cpp1z/feat-cxx17.C: Adjust.
+ * g++.dg/cpp2a/feat-cxx2a.C: Adjust.
+ * g++.dg/cpp/pr80005.C: New.
+
2020-01-20 Mark Eggleston <mark.eggleston@codethink.com>
* gfortran.dg/pr93263_1.f90: Change scan-tree-dump-not to
--- /dev/null
+// PR preprocessor/80005
+// { dg-do preprocess }
+
+#undef vector
+#define vector NOPE
+#ifdef __has_include
+
+#if !__has_include (<vector>)
+#error "Header 'vector' could not be found"
+#endif
+#define F(X) __has_include (X)
+#if !F (<vector>)
+#error "Header 'vector' could not be found" // { dg-error "not be found" }
+#endif
+
+#if __has_include ("not an escape! \") // comment
+#endif
+
+#if F ("is an escape \") gibberish ")
+#endif
+
+#else
+#error "No __has_include"
+#endif
# error "__has_include"
#endif
-// Quoted complex.h should find at least the bracket version (use operator).
-#if __has_include__ "complex.h"
-#else
-# error "complex.h"
-#endif
-
// Try known bracket header (use operator).
-#if __has_include__(<complex>)
+#if __has_include (<complex>)
#else
# error "<complex>"
#endif
// Define and use a macro to invoke the operator.
-#define sluggo(TXT) __has_include__(TXT)
+#define sluggo(TXT) __has_include(TXT)
#if sluggo(<complex>)
#else
# error "__has_include"
#endif
-// Quoted complex.h should find at least the bracket version (use operator).
-#if __has_include__ "complex.h"
-#else
-# error "complex.h"
-#endif
-
// Try known bracket header (use operator).
-#if __has_include__(<complex>)
+#if __has_include (<complex>)
#else
# error "<complex>"
#endif
// Define and use a macro to invoke the operator.
-#define sluggo(TXT) __has_include__(TXT)
+#define sluggo(TXT) __has_include(TXT)
#if sluggo(<complex>)
#else
# error "__has_include"
#endif
-// Quoted complex.h should find at least the bracket version (use operator).
-#if __has_include__ "complex.h"
-#else
-# error "complex.h"
-#endif
-
// Try known bracket header (use operator).
-#if __has_include__(<complex>)
+#if __has_include (<complex>)
#else
# error "<complex>"
#endif
// Define and use a macro to invoke the operator.
-#define sluggo(TXT) __has_include__(TXT)
+#define sluggo(TXT) __has_include(TXT)
#if sluggo(<complex>)
#else
-2020-01-17 Nathan Sidwell <nathan@acm.org>
+2020-01-20 Nathan Sidwell <nathan@acm.org>
+
+ PR preprocessor/80005
+ * include/cpplib.h (BT_HAS_ATTRIBUTE): Fix comment.
+ * internal.h (struct lexer_state): Delete in__has_include field.
+ (struct spec_nodes): Rename n__has_include{,_next}__ fields.
+ (_cpp_defined_macro_p): New.
+ (_cpp_find_file): Add has_include parm.
+ * directives.c (lex_macro_node): Combine defined,
+ __has_inline{,_next} checking.
+ (do_ifdef, do_ifndef): Use _cpp_defined_macro_p.
+ (_cpp_init_directives): Refactor.
+ * expr.c (parse_defined): Use _cpp_defined_macro_p.
+ (eval_token): Adjust parse_has_include calls.
+ (parse_has_include): Add OP parameter. Reimplement.
+ * files.c (_cpp_find_file): Add HAS_INCLUDE parm. Use it to
+ inhibit error message.
+ (_cpp_stack_include): Adjust _cpp_find_file call.
+ (_cpp_fake_include, _cpp_compare_file_date): Likewise.
+ (open_file_failed): Remove in__has_include check.
+ (_cpp_has_header): Adjust _cpp_find_file call.
+ * identifiers.c (_cpp_init_hashtable): Don't init
+ __has_include{,_next} here ...
+ * init.c (cpp_init_builtins): ... init them here. Define as
+ macros.
+ (cpp_read_main_file): Adjust _cpp_find_file call.
+ * pch.c (cpp_read_state): Adjust __has_include{,_next} access.
+ * traditional.c (_cpp_scan_out_locgical_line): Likewise.
PR preprocessor/93306
* expr.c (parse_has_include): Refactor. Check skip_eval before
{
cpp_hashnode *node = token->val.node.node;
- if (is_def_or_undef && node == pfile->spec_nodes.n_defined)
+ if (is_def_or_undef
+ && (node == pfile->spec_nodes.n_defined
+ || node == pfile->spec_nodes.n__has_include
+ || node == pfile->spec_nodes.n__has_include_next))
cpp_error (pfile, CPP_DL_ERROR,
- "\"defined\" cannot be used as a macro name");
- else if (is_def_or_undef
- && (node == pfile->spec_nodes.n__has_include__
- || node == pfile->spec_nodes.n__has_include_next__))
- cpp_error (pfile, CPP_DL_ERROR,
- "\"__has_include__\" cannot be used as a macro name");
+ "\"%s\" cannot be used as a macro name",
+ NODE_NAME (node));
else if (! (node->flags & NODE_POISONED))
return node;
}
if (node)
{
- /* Do not treat conditional macros as being defined. This is due to
- the powerpc port using conditional macros for 'vector', 'bool',
- and 'pixel' to act as conditional keywords. This messes up tests
- like #ifndef bool. */
- skip = !cpp_macro_p (node) || (node->flags & NODE_CONDITIONAL);
+ skip = !_cpp_defined_macro_p (node);
_cpp_mark_macro_used (node);
_cpp_maybe_notify_macro_use (pfile, node);
if (pfile->cb.used)
the powerpc port using conditional macros for 'vector', 'bool',
and 'pixel' to act as conditional keywords. This messes up tests
like #ifndef bool. */
- skip = (cpp_macro_p (node)
- && !(node->flags & NODE_CONDITIONAL));
+ skip = _cpp_defined_macro_p (node);
_cpp_mark_macro_used (node);
_cpp_maybe_notify_macro_use (pfile, node);
if (pfile->cb.used)
void
_cpp_init_directives (cpp_reader *pfile)
{
- unsigned int i;
- cpp_hashnode *node;
-
- for (i = 0; i < (unsigned int) N_DIRECTIVES; i++)
+ for (int i = 0; i < N_DIRECTIVES; i++)
{
- node = cpp_lookup (pfile, dtable[i].name, dtable[i].length);
+ cpp_hashnode *node = cpp_lookup (pfile, dtable[i].name, dtable[i].length);
node->is_directive = 1;
node->directive_index = i;
}
static unsigned int interpret_int_suffix (cpp_reader *, const uchar *, size_t);
static void check_promotion (cpp_reader *, const struct op *);
-static cpp_num parse_has_include (cpp_reader *, enum include_type);
+static cpp_num parse_has_include (cpp_reader *, cpp_hashnode *, include_type);
/* Token type abuse to create unary plus and minus operators. */
#define CPP_UPLUS ((enum cpp_ttype) (CPP_LAST_CPP_OP + 1))
result.unsignedp = false;
result.high = 0;
result.overflow = false;
- result.low = (node && cpp_macro_p (node)
- && !(node->flags & NODE_CONDITIONAL));
+ result.low = node && _cpp_defined_macro_p (node);
return result;
}
case CPP_NAME:
if (token->val.node.node == pfile->spec_nodes.n_defined)
return parse_defined (pfile);
- else if (token->val.node.node == pfile->spec_nodes.n__has_include__)
- return parse_has_include (pfile, IT_INCLUDE);
- else if (token->val.node.node == pfile->spec_nodes.n__has_include_next__)
- return parse_has_include (pfile, IT_INCLUDE_NEXT);
+ else if (token->val.node.node == pfile->spec_nodes.n__has_include)
+ return parse_has_include (pfile, token->val.node.node, IT_INCLUDE);
+ else if (token->val.node.node == pfile->spec_nodes.n__has_include_next)
+ return parse_has_include (pfile, token->val.node.node, IT_INCLUDE_NEXT);
else if (CPP_OPTION (pfile, cplusplus)
&& (token->val.node.node == pfile->spec_nodes.n_true
|| token->val.node.node == pfile->spec_nodes.n_false))
return lhs;
}
-/* Handle meeting "__has_include__" in a preprocessor expression. */
+/* Handle meeting "__has_include" in a preprocessor expression. */
static cpp_num
-parse_has_include (cpp_reader *pfile, enum include_type type)
+parse_has_include (cpp_reader *pfile, cpp_hashnode *op, include_type type)
{
cpp_num result;
result.overflow = false;
result.low = 0;
- pfile->state.in__has_include__++;
-
+ pfile->state.angled_headers = true;
const cpp_token *token = cpp_get_token (pfile);
bool paren = token->type == CPP_OPEN_PAREN;
if (paren)
token = cpp_get_token (pfile);
+ else
+ cpp_error (pfile, CPP_DL_ERROR,
+ "missing '(' before \"%s\" operand", NODE_NAME (op));
+ pfile->state.angled_headers = false;
bool bracket = token->type != CPP_STRING;
cpp_hashnode *node = NULL;
fname = _cpp_bracket_include (pfile);
else
cpp_error (pfile, CPP_DL_ERROR,
- "operator \"__has_include__\" requires a header string");
+ "operator \"%s\" requires a header-name", NODE_NAME (op));
if (fname)
{
if (paren && !SEEN_EOL () && cpp_get_token (pfile)->type != CPP_CLOSE_PAREN)
cpp_error (pfile, CPP_DL_ERROR,
- "missing ')' after \"__has_include__\"");
+ "missing ')' after \"%s\" operand", NODE_NAME (op));
- /* A possible controlling macro of the form #if !__has_include__ ().
- _cpp_parse_expr checks there was no other junk on the line. */
if (node)
pfile->mi_ind_cmacro = node;
- pfile->state.in__has_include__--;
-
return result;
}
_cpp_file *
_cpp_find_file (cpp_reader *pfile, const char *fname, cpp_dir *start_dir,
- bool fake, int angle_brackets, bool implicit_preinclude,
+ int angle_brackets,
+ bool fake, bool implicit_preinclude, bool has_include,
location_t loc)
{
struct cpp_file_hash_entry *entry;
return NULL;
}
- open_file_failed (pfile, file, angle_brackets, loc);
+ if (!has_include)
+ open_file_failed (pfile, file, angle_brackets, loc);
break;
}
if (!dir)
return false;
- _cpp_file *file = _cpp_find_file (pfile, fname, dir, false, angle_brackets,
- type == IT_DEFAULT, loc);
+ _cpp_file *file = _cpp_find_file (pfile, fname, dir, angle_brackets,
+ false, type == IT_DEFAULT, false, loc);
if (type == IT_DEFAULT && file == NULL)
return false;
int sysp = pfile->line_table->highest_line > 1 && pfile->buffer ? pfile->buffer->sysp : 0;
bool print_dep = CPP_OPTION (pfile, deps.style) > (angle_brackets || !!sysp);
- if (pfile->state.in__has_include__)
- return;
-
errno = file->err_no;
if (print_dep && CPP_OPTION (pfile, deps.missing_files) && errno == ENOENT)
{
void
_cpp_fake_include (cpp_reader *pfile, const char *fname)
{
- _cpp_find_file (pfile, fname, pfile->buffer->file->dir, true, 0, false, 0);
+ _cpp_find_file (pfile, fname, pfile->buffer->file->dir,
+ 0, true, false, false, 0);
}
/* Not everyone who wants to set system-header-ness on a buffer can
if (!dir)
return -1;
- file = _cpp_find_file (pfile, fname, dir, false, angle_brackets, false, 0);
+ file = _cpp_find_file (pfile, fname, dir, angle_brackets,
+ false, false, false, 0);
if (file->err_no)
return -1;
enum include_type type)
{
cpp_dir *start_dir = search_path_head (pfile, fname, angle_brackets, type);
- _cpp_file *file = _cpp_find_file (pfile, fname, start_dir,
- /*fake=*/false, angle_brackets,
- /*implicit_preinclude=*/false, 0);
+ _cpp_file *file = _cpp_find_file (pfile, fname, start_dir, angle_brackets,
+ /*fake=*/false,
+ /*implicit_preinclude=*/false,
+ /*has_include=*/true,
+ 0);
return file->err_no != ENOENT;
}
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__"));
+ /* __has_include{,_next} are inited in cpp_init_builtins. */
}
/* Tear down the identifier hash table. */
BT_PRAGMA, /* `_Pragma' operator */
BT_TIMESTAMP, /* `__TIMESTAMP__' */
BT_COUNTER, /* `__COUNTER__' */
- BT_HAS_ATTRIBUTE, /* `__has_attribute__(x)' */
+ BT_HAS_ATTRIBUTE, /* `__has_attribute(x)' */
BT_HAS_BUILTIN /* `__has_builtin(x)' */
};
if (CPP_OPTION (pfile, objc))
_cpp_define_builtin (pfile, "__OBJC__ 1");
+
+ /* These two behave as macros for #ifdef, but are evaluated
+ specially inside #if. */
+ _cpp_define_builtin (pfile, "__has_include __has_include");
+ _cpp_define_builtin (pfile, "__has_include_next __has_include_next");
+ pfile->spec_nodes.n__has_include
+ = cpp_lookup (pfile, DSC("__has_include"));
+ pfile->spec_nodes.n__has_include->flags |= NODE_DIAGNOSTIC;
+ pfile->spec_nodes.n__has_include_next
+ = cpp_lookup (pfile, DSC("__has_include_next"));
+ pfile->spec_nodes.n__has_include_next->flags |= NODE_DIAGNOSTIC;
}
/* Sanity-checks are dependent on command-line options, so it is
}
pfile->main_file
- = _cpp_find_file (pfile, fname, &pfile->no_search_path, false, 0, false,
+ = _cpp_find_file (pfile, fname, &pfile->no_search_path, /*angle=*/0,
+ /*fake=*/false, /*preinclude=*/false, /*hasinclude=*/false,
loc);
if (_cpp_find_failed (pfile->main_file))
return NULL;
/* Nonzero when parsing arguments to a function-like macro. */
unsigned char parsing_args;
- /* Nonzero if in a __has_include__ or __has_include_next__ statement. */
- unsigned char in__has_include__;
-
/* Nonzero if prevent_expansion is true only because output is
being discarded. */
unsigned char discarding_output;
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 */
+ cpp_hashnode *n__has_include; /* __has_include operator */
+ cpp_hashnode *n__has_include_next; /* __has_include_next operator */
};
typedef struct _cpp_line_note _cpp_line_note;
return pfile->line_table->depth == 1;
}
+/* True if NODE is a macro for the purposes of ifdef, defined etc. */
+inline bool _cpp_defined_macro_p (cpp_hashnode *node)
+{
+ /* Do not treat conditional macros as being defined. This is due to
+ the powerpc port using conditional macros for 'vector', 'bool',
+ and 'pixel' to act as conditional keywords. This messes up tests
+ like #ifndef bool. */
+ return cpp_macro_p (node) && !(node->flags & NODE_CONDITIONAL);
+}
+
/* In macro.c */
extern void _cpp_notify_macro_use (cpp_reader *pfile, cpp_hashnode *node);
inline void _cpp_maybe_notify_macro_use (cpp_reader *pfile, cpp_hashnode *node)
/* In files.c */
typedef struct _cpp_file _cpp_file;
extern _cpp_file *_cpp_find_file (cpp_reader *, const char *, cpp_dir *,
- bool, int, bool, location_t);
+ int angle, bool fake, bool preinclude,
+ bool has_include, location_t);
extern bool _cpp_find_failed (_cpp_file *);
extern void _cpp_mark_file_once_only (cpp_reader *, struct _cpp_file *);
extern void _cpp_fake_include (cpp_reader *, const char *);
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__"));
+ s->n__has_include = cpp_lookup (r, DSC("__has_include"));
+ s->n__has_include_next = cpp_lookup (r, DSC("__has_include_next"));
}
old_state = r->state;
ls_hash, /* After # in preprocessor conditional. */
ls_predicate, /* After the predicate, maybe paren? */
ls_answer, /* In answer to predicate. */
- ls_has_include, /* After __has_include__. */
- ls_has_include_close}; /* Looking for ')' of __has_include__. */
+ ls_has_include, /* After __has_include. */
+ ls_has_include_close}; /* Looking for ')' of __has_include. */
/* Lexing TODO: Maybe handle space in escaped newlines. Stop lex.c
from recognizing comments and directives during its lexing pass. */
continue;
}
else if (pfile->state.in_expression
- && (node == pfile->spec_nodes.n__has_include__
- || node == pfile->spec_nodes.n__has_include_next__))
+ && (node == pfile->spec_nodes.n__has_include
+ || node == pfile->spec_nodes.n__has_include_next))
{
lex_state = ls_has_include;
continue;