From patchwork Tue Sep 2 01:34:31 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ed Smith-Rowland <3dw4rd@verizon.net> X-Patchwork-Id: 384945 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 3761E1400E7 for ; Tue, 2 Sep 2014 11:35:00 +1000 (EST) DomainKey-Signature: a=rsa-sha1; c=nofws; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender :message-id:date:from:mime-version:to:subject:content-type; q= dns; s=default; b=L335r0IrVamZDBROOjEI77mSJ3RK5h4+MMI4/5qZ+Ag0Vk kGVxL5LyauJnaCKir06DU8lCTcrcmsuDQac8h4HIw3m729EOAX+iXL/jC2UCYJek LdDxxIvhIJmm6prdcLR4lr4OupHO0wQY5yR3OcQmks4fnBbkdbYRXAQweg/84= DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender :message-id:date:from:mime-version:to:subject:content-type; s= default; bh=shD2QliWFJkaXMAYHx2u6ydpPsA=; b=s6kddq/nv5WLARljyJLy hp4JkgpZ2Yem1EvqwK+ufSs6rtpHK+RqI7bWK6dB5n+YFIc1LLUfUREmC71yeIeG yzHGPugwgvhjCbYIi9r/o0QJUADDjkrYH0eu95eVJXRrCqw9TofNuiIQJ+Q8tffC WRzDihfQb0TZvRCaik3pb3k= Received: (qmail 5246 invoked by alias); 2 Sep 2014 01:34:51 -0000 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org Received: (qmail 5236 invoked by uid 89); 2 Sep 2014 01:34:50 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-1.8 required=5.0 tests=AWL, BAYES_20, RCVD_IN_DNSWL_NONE, RP_MATCHES_RCVD, SPF_PASS autolearn=ham version=3.3.2 X-HELO: vms173011pub.verizon.net Received: from vms173011pub.verizon.net (HELO vms173011pub.verizon.net) (206.46.173.11) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Tue, 02 Sep 2014 01:34:48 +0000 Received: from [192.168.1.4] ([unknown] [173.69.187.187]) by vms173011.mailsrvcs.net (Sun Java(tm) System Messaging Server 7u2-7.02 32bit (built Apr 16 2009)) with ESMTPA id <0NB9009PZ31HSB60@vms173011.mailsrvcs.net> for gcc-patches@gcc.gnu.org; Mon, 01 Sep 2014 20:34:30 -0500 (CDT) Message-id: <54051EA7.8030007@verizon.net> Date: Mon, 01 Sep 2014 21:34:31 -0400 From: Ed Smith-Rowland <3dw4rd@verizon.net> User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:31.0) Gecko/20100101 Thunderbird/31.0 MIME-version: 1.0 To: gcc-patches , Jason Merrill Subject: [PATCH C++] - SD-6 Implementation Part 1 - __has_include. Content-type: multipart/mixed; boundary=------------050802080402080102000404 Greetings, I am finally getting back to my SD-6 C++ features test work. This first part adds a __has_include__ built-in that will return true if a header exists. I also added __has_include_next__ as an extension. Clang has this extension. Both these built-ins will be wrapped in function type macros in a later patch to c-family. As written, these are available to the whole C-family rather than just C++. I think this makes a valuable addition for everyone. (I sort of wonder why this wasn't added to the actual preprocessor 20 years ago.) Bootstrapped and tested under x86_64-linux. OK? Ed 2014-09-02 Edward Smith-Rowland <3dw4rd@verizon.net> Implement SD-6: SG10 Feature Test Recommendations * internal.h (lexer_state, spec_nodes): Add in__has_include__. * directives.c: Support __has_include__ builtin. * expr.c (parse_has_include): New function to parse __has_include__ builtin; (eval_token()): Use it. * files.c (_cpp_has_header()): New funtion to look for header; (open_file_failed()): Not an error to not find a header file for __has_include__. * identifiers.c (_cpp_init_hashtable()): Add entry for __has_include__. * pch.c (cpp_read_state): Lookup __has_include__. * traditional.c (enum ls, _cpp_scan_out_logical_line()): Walk through __has_include__ statements. Index: internal.h =================================================================== --- internal.h (revision 214680) +++ internal.h (working copy) @@ -258,6 +258,9 @@ /* Nonzero when parsing arguments to a function-like macro. */ unsigned char parsing_args; + /* Nonzero to prevent macro expansion. */ + unsigned char in__has_include__; + /* Nonzero if prevent_expansion is true only because output is being discarded. */ unsigned char discarding_output; @@ -279,6 +282,8 @@ cpp_hashnode *n_true; /* C++ keyword true */ cpp_hashnode *n_false; /* C++ keyword false */ cpp_hashnode *n__VA_ARGS__; /* C99 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; @@ -645,6 +650,8 @@ extern bool _cpp_read_file_entries (cpp_reader *, FILE *); extern const char *_cpp_get_file_name (_cpp_file *); extern struct stat *_cpp_get_file_stat (_cpp_file *); +extern bool _cpp_has_header (cpp_reader *, const char *, int, + enum include_type); /* In expr.c */ extern bool _cpp_parse_expr (cpp_reader *, bool); @@ -680,6 +687,7 @@ extern void _cpp_do_file_change (cpp_reader *, enum lc_reason, const char *, linenum_type, unsigned int); extern void _cpp_pop_buffer (cpp_reader *); +extern char *_cpp_bracket_include (cpp_reader *); /* In directives.c */ struct _cpp_dir_only_callbacks Index: directives.c =================================================================== --- directives.c (revision 214680) +++ directives.c (working copy) @@ -549,6 +549,11 @@ if (is_def_or_undef && node == pfile->spec_nodes.n_defined) 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"); else if (! (node->flags & NODE_POISONED)) return node; } @@ -2601,3 +2606,12 @@ node->directive_index = i; } } + +/* Extract header file from a bracket include. Parsing starts after '<'. + The string is malloced and must be freed by the caller. */ +char * +_cpp_bracket_include(cpp_reader *pfile) +{ + return glue_header_name (pfile); +} + Index: expr.c =================================================================== --- expr.c (revision 214680) +++ expr.c (working copy) @@ -64,6 +64,8 @@ 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); + /* 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)) @@ -1048,6 +1050,10 @@ 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 (CPP_OPTION (pfile, cplusplus) && (token->val.node.node == pfile->spec_nodes.n_true || token->val.node.node == pfile->spec_nodes.n_false)) @@ -2072,3 +2078,72 @@ return lhs; } + +/* Handle meeting "__has_include__" in a preprocessor expression. */ +static cpp_num +parse_has_include (cpp_reader *pfile, enum include_type type) +{ + cpp_num result; + bool paren = false; + cpp_hashnode *node = 0; + const cpp_token *token; + bool bracket = false; + char *fname = 0; + + result.unsignedp = false; + result.high = 0; + result.overflow = false; + result.low = 0; + + pfile->state.in__has_include__++; + + token = cpp_get_token (pfile); + if (token->type == CPP_OPEN_PAREN) + { + paren = true; + token = cpp_get_token (pfile); + } + + if (token->type == CPP_STRING || token->type == CPP_HEADER_NAME) + { + if (token->type == CPP_HEADER_NAME) + bracket = true; + 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'; + node = token->val.node.node; + } + else if (token->type == CPP_LESS) + { + bracket = true; + fname = _cpp_bracket_include (pfile); + } + else + cpp_error (pfile, CPP_DL_ERROR, + "operator \"__has_include__\" requires a header string"); + + if (fname) + { + int angle_brackets = (bracket ? 1 : 0); + + if (_cpp_has_header (pfile, fname, angle_brackets, type)) + result.low = 0; + else + result.low = 1; + + XDELETEVEC (fname); + } + + if (paren && cpp_get_token (pfile)->type != CPP_CLOSE_PAREN) + cpp_error (pfile, CPP_DL_ERROR, + "missing ')' after \"__has_include__\""); + + /* 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; +} Index: files.c =================================================================== --- files.c (revision 214680) +++ files.c (working copy) @@ -1029,6 +1029,9 @@ 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) { @@ -1945,3 +1948,17 @@ return bsearch (&d, pchf->entries, pchf->count, sizeof (struct pchf_entry), pchf_compare) != NULL; } + +/* Return true if the file FNAME is found in te appropriate include file path + as indicated by ANGLE_BRACKETS. */ + +bool +_cpp_has_header (cpp_reader *pfile, const char *fname, int angle_brackets, + enum include_type type) +{ + cpp_dir *start_dir = search_path_head (pfile, fname, angle_brackets, type); + return _cpp_find_failed (_cpp_find_file (pfile, fname, start_dir, + /*fake=*/false, angle_brackets, + /*implicit_preinclude=*/false)); +} + Index: identifiers.c =================================================================== --- identifiers.c (revision 214680) +++ identifiers.c (working copy) @@ -72,6 +72,8 @@ s->n_false = cpp_lookup (pfile, DSC("false")); s->n__VA_ARGS__ = cpp_lookup (pfile, DSC("__VA_ARGS__")); s->n__VA_ARGS__->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__")); } /* Tear down the identifier hash table. */ Index: pch.c =================================================================== --- pch.c (revision 214680) +++ pch.c (working copy) @@ -833,6 +833,8 @@ s->n_true = cpp_lookup (r, DSC("true")); s->n_false = cpp_lookup (r, DSC("false")); s->n__VA_ARGS__ = cpp_lookup (r, DSC("__VA_ARGS__")); + 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; Index: traditional.c =================================================================== --- traditional.c (revision 214680) +++ traditional.c (working copy) @@ -74,7 +74,9 @@ 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_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 from recognizing comments and directives during its lexing pass. */ @@ -524,6 +526,13 @@ 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; @@ -547,6 +556,8 @@ 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; @@ -584,7 +595,8 @@ 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; } break; @@ -665,7 +677,8 @@ lex_state = ls_none; else if (lex_state == ls_hash || lex_state == ls_predicate - || lex_state == ls_defined) + || lex_state == ls_defined + || lex_state == ls_has_include) lex_state = ls_none; /* ls_answer and ls_defined_close keep going until ')'. */