From: Nathan Sidwell Date: Tue, 28 Jan 2020 15:58:29 +0000 (-0800) Subject: preprocessor: Make __has_include a builtin macro [PR93452] X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=3d056cbfb3484f4037b34c908b26e1c6776c86b5;p=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. --- diff --git a/gcc/testsuite/c-c++-common/cpp/pr93452-1.c b/gcc/testsuite/c-c++-common/cpp/pr93452-1.c new file mode 100644 index 00000000000..f0986e49238 --- /dev/null +++ b/gcc/testsuite/c-c++-common/cpp/pr93452-1.c @@ -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} } } */ diff --git a/gcc/testsuite/c-c++-common/cpp/pr93452-2.c b/gcc/testsuite/c-c++-common/cpp/pr93452-2.c new file mode 100644 index 00000000000..c9ab0e9f763 --- /dev/null +++ b/gcc/testsuite/c-c++-common/cpp/pr93452-2.c @@ -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} } } */ diff --git a/libcpp/ChangeLog b/libcpp/ChangeLog index ea9d60215e5..f749622a5f7 100644 --- a/libcpp/ChangeLog +++ b/libcpp/ChangeLog @@ -1,3 +1,19 @@ +2020-01-28 Nathan Sidwell + + 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 * configure: Regenerate. diff --git a/libcpp/directives.c b/libcpp/directives.c index 10735c8c668..bbfdfcd3368 100644 --- a/libcpp/directives.c +++ b/libcpp/directives.c @@ -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)); diff --git a/libcpp/expr.c b/libcpp/expr.c index 6c56803e3b0..2ae9be07c1a 100644 --- a/libcpp/expr.c +++ b/libcpp/expr.c @@ -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; -} diff --git a/libcpp/include/cpplib.h b/libcpp/include/cpplib.h index 56cbbd82750..07caadb88e7 100644 --- a/libcpp/include/cpplib.h +++ b/libcpp/include/cpplib.h @@ -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)) diff --git a/libcpp/init.c b/libcpp/init.c index e798140ef8b..a3cd8e28f62 100644 --- a/libcpp/init.c +++ b/libcpp/init.c @@ -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 diff --git a/libcpp/internal.h b/libcpp/internal.h index 5453c3bff85..97d9bdbea77 100644 --- a/libcpp/internal.h +++ b/libcpp/internal.h @@ -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; diff --git a/libcpp/macro.c b/libcpp/macro.c index dbd7a284662..ec3f8b7b73c 100644 --- a/libcpp/macro.c +++ b/libcpp/macro.c @@ -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) diff --git a/libcpp/pch.c b/libcpp/pch.c index e631050936b..fcdf3875d0b 100644 --- a/libcpp/pch.c +++ b/libcpp/pch.c @@ -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; diff --git a/libcpp/traditional.c b/libcpp/traditional.c index ff06d31a897..039fcfe27f5 100644 --- a/libcpp/traditional.c +++ b/libcpp/traditional.c @@ -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 ')'. */