preprocessor: Make __has_include a builtin macro [PR93452]

The clever hack of '#define __has_include __has_include' breaks -dD
and -fdirectives-only, because that emits definitions.  This turns
__has_include into a proper builtin macro.  Thus it's never emitted
via -dD, and because use outside of directive processing is undefined,
we can just expand it anywhere.

	PR preprocessor/93452
	* internal.h (struct spec_nodes): Drop n__has_include{,_next}.
	* directives.c (lex_macro_node): Don't check __has_include redef.
	* expr.c (eval_token): Drop __has_include eval.
	(parse_has_include): Move to ...
	* macro.c (builtin_has_include): ... here.
	(_cpp_builtin_macro_text): Eval __has_include{,_next}.
	* include/cpplib.h (enum cpp_builtin_type): Add BT_HAS_INCLUDE{,_NEXT}.
	* init.c (builtin_array): Add them.
	(cpp_init_builtins): Drop __has_include{,_next} init here ...
	* pch.c (cpp_read_state): ... and here.
	* traditional.c (enum ls): Drop has_include states ...
	(_cpp_scan_out_logical_line): ... and here.
This commit is contained in:
Nathan Sidwell 2020-01-28 07:58:29 -08:00
parent a5d81aaab6
commit 3d056cbfb3
11 changed files with 103 additions and 93 deletions

View File

@ -0,0 +1,10 @@
/* { dg-do preprocess } */
/* { dg-additional-options "-fdirectives-only" } */
int main ()
{
return 0;
}
/* A regexp that doesn't match itself! */
/* { dg-final { scan-file-not pr93452-1.i {_[_]has_include} } } */

View File

@ -0,0 +1,11 @@
/* { dg-do preprocess } */
/* { dg-additional-options "-dD" } */
#if __has_include ("who cares" )
#endif
int main ()
{
return 0;
}
/* { dg-final { scan-file-not pr93452-2.i {__has_include} } } */

View File

@ -1,3 +1,19 @@
2020-01-28 Nathan Sidwell <nathan@acm.org>
PR preprocessor/93452
* internal.h (struct spec_nodes): Drop n__has_include{,_next}.
* directives.c (lex_macro_node): Don't check __has_include redef.
* expr.c (eval_token): Drop __has_include eval.
(parse_has_include): Move to ...
* macro.c (builtin_has_include): ... here.
(_cpp_builtin_macro_text): Eval __has_include{,_next}.
* include/cpplib.h (enum cpp_builtin_type): Add BT_HAS_INCLUDE{,_NEXT}.
* init.c (builtin_array): Add them.
(cpp_init_builtins): Drop __has_include{,_next} init here ...
* pch.c (cpp_read_state): ... and here.
* traditional.c (enum ls): Drop has_include states ...
(_cpp_scan_out_logical_line): ... and here.
2020-01-27 Andrew Burgess <andrew.burgess@embecosm.com>
* configure: Regenerate.

View File

@ -596,9 +596,7 @@ lex_macro_node (cpp_reader *pfile, bool is_def_or_undef)
cpp_hashnode *node = token->val.node.node;
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))
&& node == pfile->spec_nodes.n_defined)
cpp_error (pfile, CPP_DL_ERROR,
"\"%s\" cannot be used as a macro name",
NODE_NAME (node));

View File

@ -64,8 +64,6 @@ static unsigned int interpret_float_suffix (cpp_reader *, const uchar *, size_t)
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 *, 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))
#define CPP_UMINUS ((enum cpp_ttype) (CPP_LAST_CPP_OP + 2))
@ -1159,10 +1157,6 @@ eval_token (cpp_reader *pfile, const cpp_token *token,
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, 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))
@ -2189,55 +2183,3 @@ num_div_op (cpp_reader *pfile, cpp_num lhs, cpp_num rhs, enum cpp_ttype op,
return lhs;
}
/* Handle meeting "__has_include" in a preprocessor expression. */
static cpp_num
parse_has_include (cpp_reader *pfile, cpp_hashnode *op, include_type type)
{
cpp_num result;
result.unsignedp = false;
result.high = 0;
result.overflow = false;
result.low = 0;
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;
char *fname = NULL;
if (token->type == CPP_STRING || token->type == CPP_HEADER_NAME)
{
fname = XNEWVEC (char, token->val.str.len - 1);
memcpy (fname, token->val.str.text + 1, token->val.str.len - 2);
fname[token->val.str.len - 2] = '\0';
}
else if (token->type == CPP_LESS)
fname = _cpp_bracket_include (pfile);
else
cpp_error (pfile, CPP_DL_ERROR,
"operator \"%s\" requires a header-name", NODE_NAME (op));
if (fname)
{
/* Do not do the lookup if we're skipping, that's unnecessary
IO. */
if (!pfile->state.skip_eval
&& _cpp_has_header (pfile, fname, bracket, type))
result.low = 1;
XDELETEVEC (fname);
}
if (paren && !SEEN_EOL () && cpp_get_token (pfile)->type != CPP_CLOSE_PAREN)
cpp_error (pfile, CPP_DL_ERROR,
"missing ')' after \"%s\" operand", NODE_NAME (op));
return result;
}

View File

@ -860,7 +860,9 @@ enum cpp_builtin_type
BT_TIMESTAMP, /* `__TIMESTAMP__' */
BT_COUNTER, /* `__COUNTER__' */
BT_HAS_ATTRIBUTE, /* `__has_attribute(x)' */
BT_HAS_BUILTIN /* `__has_builtin(x)' */
BT_HAS_BUILTIN, /* `__has_builtin(x)' */
BT_HAS_INCLUDE, /* `__has_include(x)' */
BT_HAS_INCLUDE_NEXT, /* `__has_include_next(x)' */
};
#define CPP_HASHNODE(HNODE) ((cpp_hashnode *) (HNODE))

View File

@ -404,6 +404,8 @@ static const struct builtin_macro builtin_array[] =
B("__has_attribute", BT_HAS_ATTRIBUTE, true),
B("__has_cpp_attribute", BT_HAS_ATTRIBUTE, true),
B("__has_builtin", BT_HAS_BUILTIN, true),
B("__has_include", BT_HAS_INCLUDE, true),
B("__has_include_next",BT_HAS_INCLUDE_NEXT, true),
/* Keep builtins not used for -traditional-cpp at the end, and
update init_builtins() if any more are added. */
B("_Pragma", BT_PRAGMA, true),
@ -578,17 +580,6 @@ cpp_init_builtins (cpp_reader *pfile, int hosted)
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

View File

@ -290,8 +290,6 @@ struct spec_nodes
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 */
};
typedef struct _cpp_line_note _cpp_line_note;

View File

@ -336,6 +336,56 @@ unsigned num_expanded_macros_counter = 0;
from macro expansion. */
unsigned num_macro_tokens_counter = 0;
/* Handle meeting "__has_include" builtin macro. */
static int
builtin_has_include (cpp_reader *pfile, cpp_hashnode *op, bool has_next)
{
int result = 0;
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;
char *fname = NULL;
if (token->type == CPP_STRING || token->type == CPP_HEADER_NAME)
{
fname = XNEWVEC (char, token->val.str.len - 1);
memcpy (fname, token->val.str.text + 1, token->val.str.len - 2);
fname[token->val.str.len - 2] = '\0';
}
else if (token->type == CPP_LESS)
fname = _cpp_bracket_include (pfile);
else
cpp_error (pfile, CPP_DL_ERROR,
"operator \"%s\" requires a header-name", NODE_NAME (op));
if (fname)
{
/* Do not do the lookup if we're skipping, that's unnecessary
IO. */
if (!pfile->state.skip_eval
&& _cpp_has_header (pfile, fname, bracket,
has_next ? IT_INCLUDE_NEXT : IT_INCLUDE))
result = 1;
XDELETEVEC (fname);
}
if (paren && !SEEN_EOL () && cpp_get_token (pfile)->type != CPP_CLOSE_PAREN)
cpp_error (pfile, CPP_DL_ERROR,
"missing ')' after \"%s\" operand", NODE_NAME (op));
return result;
}
/* Emits a warning if NODE is a macro defined in the main file that
has not been used. */
int
@ -572,6 +622,12 @@ _cpp_builtin_macro_text (cpp_reader *pfile, cpp_hashnode *node,
case BT_HAS_BUILTIN:
number = pfile->cb.has_builtin (pfile);
break;
case BT_HAS_INCLUDE:
case BT_HAS_INCLUDE_NEXT:
number = builtin_has_include (pfile, node,
node->value.builtin == BT_HAS_INCLUDE_NEXT);
break;
}
if (result == NULL)

View File

@ -811,8 +811,6 @@ cpp_read_state (cpp_reader *r, const char *name, FILE *f,
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"));
}
old_state = r->state;

View File

@ -77,9 +77,8 @@ enum ls {ls_none = 0, /* Normal state. */
ls_defined_close, /* Looking for ')' of defined(). */
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_answer /* In answer to predicate. */
};
/* Lexing TODO: Maybe handle space in escaped newlines. Stop lex.c
from recognizing comments and directives during its lexing pass. */
@ -564,13 +563,6 @@ _cpp_scan_out_logical_line (cpp_reader *pfile, cpp_macro *macro,
lex_state = ls_defined;
continue;
}
else if (pfile->state.in_expression
&& (node == pfile->spec_nodes.n__has_include
|| node == pfile->spec_nodes.n__has_include_next))
{
lex_state = ls_has_include;
continue;
}
}
break;
@ -594,8 +586,6 @@ _cpp_scan_out_logical_line (cpp_reader *pfile, cpp_macro *macro,
lex_state = ls_answer;
else if (lex_state == ls_defined)
lex_state = ls_defined_close;
else if (lex_state == ls_has_include)
lex_state = ls_has_include_close;
}
break;
@ -729,8 +719,7 @@ _cpp_scan_out_logical_line (cpp_reader *pfile, cpp_macro *macro,
goto new_context;
}
}
else if (lex_state == ls_answer || lex_state == ls_defined_close
|| lex_state == ls_has_include_close)
else if (lex_state == ls_answer || lex_state == ls_defined_close)
lex_state = ls_none;
}
break;
@ -811,8 +800,7 @@ _cpp_scan_out_logical_line (cpp_reader *pfile, cpp_macro *macro,
lex_state = ls_none;
else if (lex_state == ls_hash
|| lex_state == ls_predicate
|| lex_state == ls_defined
|| lex_state == ls_has_include)
|| lex_state == ls_defined)
lex_state = ls_none;
/* ls_answer and ls_defined_close keep going until ')'. */