diff options
author | Nathan Sidwell <nathan@acm.org> | 2020-01-20 05:39:59 -0800 |
---|---|---|
committer | Nathan Sidwell <nathan@acm.org> | 2020-01-20 05:39:59 -0800 |
commit | ad1a3914ae8d67c94b0d2428e3f9672e7db491a1 (patch) | |
tree | 60f0771d802b20be5b8a827738e48324dcb24d2b /libcpp/expr.c | |
parent | e82ba180d6641a1e2bad1ac327234fc1cda658ef (diff) | |
download | gcc-ad1a3914ae8d67c94b0d2428e3f9672e7db491a1.zip gcc-ad1a3914ae8d67c94b0d2428e3f9672e7db491a1.tar.gz gcc-ad1a3914ae8d67c94b0d2428e3f9672e7db491a1.tar.bz2 |
[PR 80005] Fix __has_include
__has_include is funky in that it is macro-like from the POV of #ifdef and
friends, but lexes its parenthesize argument #include-like. We were
failing the second part of that, because we used a forwarding macro to an
internal name, and hence always lexed the argument in macro-parameter
context. We componded that by not setting the right flag when lexing, so
it didn't even know. Mostly users got lucky.
This reimplements the handline.
1) Remove the forwarding, but declare object-like macros that
expand to themselves. This satisfies the #ifdef requirement
2) Correctly set angled_brackets when lexing the parameter. This tells
the lexer (a) <...> is a header name and (b) "..." is too (not a string).
3) Remove the in__has_include lexer state, just tell find_file that that's
what's happenning, so it doesn't emit an error.
We lose the (undocumented) ability to #undef __has_include. That may well
have been an accident of implementation. There are no tests for it.
We gain __has_include behaviour for all users of the preprocessors -- not
just the C-family ones that defined a forwarding macro.
libcpp/
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.
gcc/c-family/
PR preprocessor/80005
* c-cppbuiltins.c (c_cpp_builtins): Don't define __has_include{,_next}.
gcc/testsuite/
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.
Diffstat (limited to 'libcpp/expr.c')
-rw-r--r-- | libcpp/expr.c | 32 |
1 files changed, 15 insertions, 17 deletions
diff --git a/libcpp/expr.c b/libcpp/expr.c index 317faf5..df21a4b 100644 --- a/libcpp/expr.c +++ b/libcpp/expr.c @@ -64,7 +64,7 @@ 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 *, 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)) @@ -1088,8 +1088,7 @@ parse_defined (cpp_reader *pfile) 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; } @@ -1160,10 +1159,10 @@ 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, 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)) @@ -2190,9 +2189,9 @@ 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. */ +/* 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; @@ -2201,12 +2200,15 @@ parse_has_include (cpp_reader *pfile, enum include_type type) 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; @@ -2222,7 +2224,7 @@ parse_has_include (cpp_reader *pfile, enum include_type type) 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) { @@ -2237,14 +2239,10 @@ parse_has_include (cpp_reader *pfile, enum include_type type) 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; } |