mirror of git://gcc.gnu.org/git/gcc.git
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:
parent
a5d81aaab6
commit
3d056cbfb3
|
@ -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} } } */
|
|
@ -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} } } */
|
|
@ -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>
|
2020-01-27 Andrew Burgess <andrew.burgess@embecosm.com>
|
||||||
|
|
||||||
* configure: Regenerate.
|
* configure: Regenerate.
|
||||||
|
|
|
@ -596,9 +596,7 @@ lex_macro_node (cpp_reader *pfile, bool is_def_or_undef)
|
||||||
cpp_hashnode *node = token->val.node.node;
|
cpp_hashnode *node = token->val.node.node;
|
||||||
|
|
||||||
if (is_def_or_undef
|
if (is_def_or_undef
|
||||||
&& (node == pfile->spec_nodes.n_defined
|
&& 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,
|
cpp_error (pfile, CPP_DL_ERROR,
|
||||||
"\"%s\" cannot be used as a macro name",
|
"\"%s\" cannot be used as a macro name",
|
||||||
NODE_NAME (node));
|
NODE_NAME (node));
|
||||||
|
|
|
@ -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 unsigned int interpret_int_suffix (cpp_reader *, const uchar *, size_t);
|
||||||
static void check_promotion (cpp_reader *, const struct op *);
|
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. */
|
/* Token type abuse to create unary plus and minus operators. */
|
||||||
#define CPP_UPLUS ((enum cpp_ttype) (CPP_LAST_CPP_OP + 1))
|
#define CPP_UPLUS ((enum cpp_ttype) (CPP_LAST_CPP_OP + 1))
|
||||||
#define CPP_UMINUS ((enum cpp_ttype) (CPP_LAST_CPP_OP + 2))
|
#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:
|
case CPP_NAME:
|
||||||
if (token->val.node.node == pfile->spec_nodes.n_defined)
|
if (token->val.node.node == pfile->spec_nodes.n_defined)
|
||||||
return parse_defined (pfile);
|
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)
|
else if (CPP_OPTION (pfile, cplusplus)
|
||||||
&& (token->val.node.node == pfile->spec_nodes.n_true
|
&& (token->val.node.node == pfile->spec_nodes.n_true
|
||||||
|| token->val.node.node == pfile->spec_nodes.n_false))
|
|| 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;
|
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;
|
|
||||||
}
|
|
||||||
|
|
|
@ -860,7 +860,9 @@ enum cpp_builtin_type
|
||||||
BT_TIMESTAMP, /* `__TIMESTAMP__' */
|
BT_TIMESTAMP, /* `__TIMESTAMP__' */
|
||||||
BT_COUNTER, /* `__COUNTER__' */
|
BT_COUNTER, /* `__COUNTER__' */
|
||||||
BT_HAS_ATTRIBUTE, /* `__has_attribute(x)' */
|
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))
|
#define CPP_HASHNODE(HNODE) ((cpp_hashnode *) (HNODE))
|
||||||
|
|
|
@ -404,6 +404,8 @@ static const struct builtin_macro builtin_array[] =
|
||||||
B("__has_attribute", BT_HAS_ATTRIBUTE, true),
|
B("__has_attribute", BT_HAS_ATTRIBUTE, true),
|
||||||
B("__has_cpp_attribute", BT_HAS_ATTRIBUTE, true),
|
B("__has_cpp_attribute", BT_HAS_ATTRIBUTE, true),
|
||||||
B("__has_builtin", BT_HAS_BUILTIN, 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
|
/* Keep builtins not used for -traditional-cpp at the end, and
|
||||||
update init_builtins() if any more are added. */
|
update init_builtins() if any more are added. */
|
||||||
B("_Pragma", BT_PRAGMA, true),
|
B("_Pragma", BT_PRAGMA, true),
|
||||||
|
@ -578,17 +580,6 @@ cpp_init_builtins (cpp_reader *pfile, int hosted)
|
||||||
|
|
||||||
if (CPP_OPTION (pfile, objc))
|
if (CPP_OPTION (pfile, objc))
|
||||||
_cpp_define_builtin (pfile, "__OBJC__ 1");
|
_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
|
/* Sanity-checks are dependent on command-line options, so it is
|
||||||
|
|
|
@ -290,8 +290,6 @@ struct spec_nodes
|
||||||
cpp_hashnode *n_false; /* C++ keyword false */
|
cpp_hashnode *n_false; /* C++ keyword false */
|
||||||
cpp_hashnode *n__VA_ARGS__; /* C99 vararg macros */
|
cpp_hashnode *n__VA_ARGS__; /* C99 vararg macros */
|
||||||
cpp_hashnode *n__VA_OPT__; /* C++ 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;
|
typedef struct _cpp_line_note _cpp_line_note;
|
||||||
|
|
|
@ -336,6 +336,56 @@ unsigned num_expanded_macros_counter = 0;
|
||||||
from macro expansion. */
|
from macro expansion. */
|
||||||
unsigned num_macro_tokens_counter = 0;
|
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
|
/* Emits a warning if NODE is a macro defined in the main file that
|
||||||
has not been used. */
|
has not been used. */
|
||||||
int
|
int
|
||||||
|
@ -572,6 +622,12 @@ _cpp_builtin_macro_text (cpp_reader *pfile, cpp_hashnode *node,
|
||||||
case BT_HAS_BUILTIN:
|
case BT_HAS_BUILTIN:
|
||||||
number = pfile->cb.has_builtin (pfile);
|
number = pfile->cb.has_builtin (pfile);
|
||||||
break;
|
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)
|
if (result == NULL)
|
||||||
|
|
|
@ -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_false = cpp_lookup (r, DSC("false"));
|
||||||
s->n__VA_ARGS__ = cpp_lookup (r, DSC("__VA_ARGS__"));
|
s->n__VA_ARGS__ = cpp_lookup (r, DSC("__VA_ARGS__"));
|
||||||
s->n__VA_OPT__ = cpp_lookup (r, DSC("__VA_OPT__"));
|
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;
|
old_state = r->state;
|
||||||
|
|
|
@ -77,9 +77,8 @@ enum ls {ls_none = 0, /* Normal state. */
|
||||||
ls_defined_close, /* Looking for ')' of defined(). */
|
ls_defined_close, /* Looking for ')' of defined(). */
|
||||||
ls_hash, /* After # in preprocessor conditional. */
|
ls_hash, /* After # in preprocessor conditional. */
|
||||||
ls_predicate, /* After the predicate, maybe paren? */
|
ls_predicate, /* After the predicate, maybe paren? */
|
||||||
ls_answer, /* In answer to predicate. */
|
ls_answer /* In answer to predicate. */
|
||||||
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
|
/* Lexing TODO: Maybe handle space in escaped newlines. Stop lex.c
|
||||||
from recognizing comments and directives during its lexing pass. */
|
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;
|
lex_state = ls_defined;
|
||||||
continue;
|
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;
|
break;
|
||||||
|
|
||||||
|
@ -594,8 +586,6 @@ _cpp_scan_out_logical_line (cpp_reader *pfile, cpp_macro *macro,
|
||||||
lex_state = ls_answer;
|
lex_state = ls_answer;
|
||||||
else if (lex_state == ls_defined)
|
else if (lex_state == ls_defined)
|
||||||
lex_state = ls_defined_close;
|
lex_state = ls_defined_close;
|
||||||
else if (lex_state == ls_has_include)
|
|
||||||
lex_state = ls_has_include_close;
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -729,8 +719,7 @@ _cpp_scan_out_logical_line (cpp_reader *pfile, cpp_macro *macro,
|
||||||
goto new_context;
|
goto new_context;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (lex_state == ls_answer || lex_state == ls_defined_close
|
else if (lex_state == ls_answer || lex_state == ls_defined_close)
|
||||||
|| lex_state == ls_has_include_close)
|
|
||||||
lex_state = ls_none;
|
lex_state = ls_none;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -811,8 +800,7 @@ _cpp_scan_out_logical_line (cpp_reader *pfile, cpp_macro *macro,
|
||||||
lex_state = ls_none;
|
lex_state = ls_none;
|
||||||
else if (lex_state == ls_hash
|
else if (lex_state == ls_hash
|
||||||
|| lex_state == ls_predicate
|
|| lex_state == ls_predicate
|
||||||
|| lex_state == ls_defined
|
|| lex_state == ls_defined)
|
||||||
|| lex_state == ls_has_include)
|
|
||||||
lex_state = ls_none;
|
lex_state = ls_none;
|
||||||
|
|
||||||
/* ls_answer and ls_defined_close keep going until ')'. */
|
/* ls_answer and ls_defined_close keep going until ')'. */
|
||||||
|
|
Loading…
Reference in New Issue