From patchwork Mon Aug 20 12:38:47 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Nathan Sidwell X-Patchwork-Id: 959665 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=gcc.gnu.org (client-ip=209.132.180.131; helo=sourceware.org; envelope-from=gcc-patches-return-483967-incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=acm.org Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.b="kTzcy3hk"; dkim-atps=neutral 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 41vCzV634pz9s9F for ; Mon, 20 Aug 2018 22:39:01 +1000 (AEST) Received: (qmail 112792 invoked by alias); 20 Aug 2018 12:38:55 -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 112783 invoked by uid 89); 20 Aug 2018 12:38:54 -0000 Authentication-Results: sourceware.org; auth=none X-Spam-SWARE-Status: No, score=-16.1 required=5.0 tests=BAYES_00, FREEMAIL_FROM, GIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3, KAM_ASCII_DIVIDERS, RCVD_IN_DNSWL_NONE, SPF_PASS autolearn=ham version=3.3.2 spammy=H*r:IPv6, Hx-spam-relays-external:sk:mail-yb, H*r:sk:mail-yb, HX-HELO:sk:mail-yb X-HELO: mail-yb0-f179.google.com Received: from mail-yb0-f179.google.com (HELO mail-yb0-f179.google.com) (209.85.213.179) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Mon, 20 Aug 2018 12:38:51 +0000 Received: by mail-yb0-f179.google.com with SMTP id d4-v6so577247ybl.0 for ; Mon, 20 Aug 2018 05:38:51 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=sender:to:from:subject:message-id:date:user-agent:mime-version :content-language; bh=0UeGjHRStivjgB0Q80JFodsjUMump0O3HAM/Gbwd3nQ=; b=kTzcy3hkpxH67IPR4RkwWg09XL+pwTqmgqXMJgOeOFCI3Ui82yMqbW2NP6+SI7wNz1 pmJZcKe47JMJVfuay9yTsI+g6ngshZ0zffqmGpXhsgYUijMasStzUwNZ85MvavvpftMy 07Ls96f8xsD5hxNXaFqCHK1lQa3SgCN4ezeI2bFbsego2r2TffVmmCerjjtgO6PeHZBx 4nZYmCVY4sc5Lg4EyjiiPj8/JZnIX28V2Uln37RSnj1Objp8MqbZMtejktMSO0aDj8ws Sw/PHz/Thl8nDh6oRiS104VMVCETLvmEVgB0bHQ2DZKInl8OeuBvLmrfHwCW4biobzE7 fI/Q== Received: from ?IPv6:2620:10d:c0a3:20fb:7500:e7fb:4a6f:2254? ([2620:10d:c091:200::5c29]) by smtp.googlemail.com with ESMTPSA id s63-v6sm4961716ywd.63.2018.08.20.05.38.48 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Mon, 20 Aug 2018 05:38:49 -0700 (PDT) Sender: Nathan Sidwell To: GCC Patches From: Nathan Sidwell Subject: [PATCH] #assert becomes macro-like Message-ID: <606feb9a-fa6c-6023-3d8c-9b8ca4211713@acm.org> Date: Mon, 20 Aug 2018 08:38:47 -0400 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:52.0) Gecko/20100101 Thunderbird/52.9.1 MIME-Version: 1.0 The preprocessor has cpp-asserts, a deprecated extension. They look like macros in that they have a tokenized body, but there's a chain of them hanging off an assert node, rather than having any parms. This patch removes their 'answer' struct, and extends cpp_macro to represent them. the enum macro_kind gains a value, and the parameter pointer is now held in a union keyed off the macro kind. The hashnode value union still contains 'answer' and 'macro' fields, even though they have the same underlying type. Clean up of that union will happen later. The remaining changes are mechanical (the answer struct already used the trailing array hack for the tokens, so drops straight into the update cpp_macro representation). booted & tested on x86_64-linux, committing to trunk. nathan 2018-08-20 Nathan Sidwell libcpp/ * include/cpp-id-data.h (struct answer): Delete. * include/cpplib.h (struct answer): Don't forward-declare. (enum cpp_macro_kind): Add cmk_assert. (struct cpp_macro): Union parms and next assert chain. (union _cpp_hashnode_value): 'answer' field is cpp_macro. * directives.c (parse_answer): Convert to use cpp_macro. Return true on success. (parse_assertion, find_answer, _cpp_test_assertion, cpp_do_assert) (cpp_do_unassert): Convert to use cpp_macro. * macro.c (warn_of_redefinition, _cpp_new_macro) (check_trad_stringification, cpp_macro_definition): Adjust macro parm access. * traditional.c (_cpp_replacement_text_len) (_cpp_copy_replacement_text, _cpp_create_trad_definition): Likewise. gcc/c-family/ * c-ada-spec.c (macro_length, dump_ada_macros): Adjust macro parm access. Index: gcc/c-family/c-ada-spec.c =================================================================== --- gcc/c-family/c-ada-spec.c (revision 263656) +++ gcc/c-family/c-ada-spec.c (working copy) @@ -69,7 +69,7 @@ macro_length (const cpp_macro *macro, in (*param_len)++; for (i = 0; i < macro->paramc; i++) { - cpp_hashnode *param = macro->params[i]; + cpp_hashnode *param = macro->parm.params[i]; *param_len += NODE_LEN (param); @@ -101,7 +101,7 @@ macro_length (const cpp_macro *macro, in if (token->type == CPP_MACRO_ARG) *buffer_len += - NODE_LEN (macro->params[token->val.macro_arg.arg_no - 1]); + NODE_LEN (macro->parm.params[token->val.macro_arg.arg_no - 1]); else /* Include enough extra space to handle e.g. special characters. */ *buffer_len += (cpp_token_len (token) + 1) * 8; @@ -252,7 +252,7 @@ dump_ada_macros (pretty_printer *pp, con *buf_param++ = '('; for (i = 0; i < macro->paramc; i++) { - cpp_hashnode *param = macro->params[i]; + cpp_hashnode *param = macro->parm.params[i]; memcpy (buf_param, NODE_NAME (param), NODE_LEN (param)); buf_param += NODE_LEN (param); @@ -291,7 +291,7 @@ dump_ada_macros (pretty_printer *pp, con case CPP_MACRO_ARG: { cpp_hashnode *param = - macro->params[token->val.macro_arg.arg_no - 1]; + macro->parm.params[token->val.macro_arg.arg_no - 1]; memcpy (buffer, NODE_NAME (param), NODE_LEN (param)); buffer += NODE_LEN (param); } Index: libcpp/directives.c =================================================================== --- libcpp/directives.c (revision 263656) +++ libcpp/directives.c (working copy) @@ -124,9 +124,9 @@ static const cpp_token *get_token_no_pad static const cpp_token *get__Pragma_string (cpp_reader *); static void destringize_and_run (cpp_reader *, const cpp_string *, source_location); -static int parse_answer (cpp_reader *, struct answer **, int, source_location); -static cpp_hashnode *parse_assertion (cpp_reader *, struct answer **, int); -static struct answer ** find_answer (cpp_hashnode *, const struct answer *); +static bool parse_answer (cpp_reader *, int, source_location, cpp_macro **); +static cpp_hashnode *parse_assertion (cpp_reader *, int, cpp_macro **); +static cpp_macro **find_answer (cpp_hashnode *, const cpp_macro *); static void handle_assertion (cpp_reader *, const char *, int); static void do_pragma_push_macro (cpp_reader *); static void do_pragma_pop_macro (cpp_reader *); @@ -2149,17 +2149,13 @@ push_conditional (cpp_reader *pfile, int storage, i.e. the #assert case. Returns 0 on success, and sets ANSWERP to point to the answer. PRED_LOC is the location of the predicate. */ -static int -parse_answer (cpp_reader *pfile, struct answer **answerp, int type, - source_location pred_loc) +static bool +parse_answer (cpp_reader *pfile, int type, source_location pred_loc, + cpp_macro **answer_ptr) { - const cpp_token *paren; - struct answer *answer; - unsigned int acount; - /* In a conditional, it is legal to not have an open paren. We should save the following token in this case. */ - paren = cpp_get_token (pfile); + const cpp_token *paren = cpp_get_token (pfile); /* If not a paren, see if we're OK. */ if (paren->type != CPP_OPEN_PAREN) @@ -2169,23 +2165,26 @@ parse_answer (cpp_reader *pfile, struct if (type == T_IF) { _cpp_backup_tokens (pfile, 1); - return 0; + return true; } /* #unassert with no answer is valid - it removes all answers. */ if (type == T_UNASSERT && paren->type == CPP_EOF) - return 0; + return true; cpp_error_with_line (pfile, CPP_DL_ERROR, pred_loc, 0, "missing '(' after predicate"); - return 1; + return false; } - for (acount = 0;; acount++) + cpp_macro *answer = _cpp_new_macro (pfile, cmk_assert, + _cpp_reserve_room (pfile, 0, + sizeof (cpp_macro))); + answer->parm.next = NULL; + unsigned count = 0; + for (;;) { - size_t room_needed; const cpp_token *token = cpp_get_token (pfile); - cpp_token *dest; if (token->type == CPP_CLOSE_PAREN) break; @@ -2193,57 +2192,51 @@ parse_answer (cpp_reader *pfile, struct if (token->type == CPP_EOF) { cpp_error (pfile, CPP_DL_ERROR, "missing ')' to complete answer"); - return 1; + return false; } - /* struct answer includes the space for one token. */ - room_needed = (sizeof (struct answer) + acount * sizeof (cpp_token)); - - if (BUFF_ROOM (pfile->a_buff) < room_needed) - _cpp_extend_buff (pfile, &pfile->a_buff, sizeof (struct answer)); - - dest = &((struct answer *) BUFF_FRONT (pfile->a_buff))->first[acount]; - *dest = *token; - - /* Drop whitespace at start, for answer equivalence purposes. */ - if (acount == 0) - dest->flags &= ~PREV_WHITE; + answer = (cpp_macro *)_cpp_reserve_room + (pfile, sizeof (cpp_macro) + count * sizeof (cpp_token), + sizeof (cpp_token)); + answer->exp.tokens[count++] = *token; } - if (acount == 0) + if (!count) { cpp_error (pfile, CPP_DL_ERROR, "predicate's answer is empty"); - return 1; + return false; } - answer = (struct answer *) BUFF_FRONT (pfile->a_buff); - answer->count = acount; - answer->next = NULL; - *answerp = answer; + /* Drop whitespace at start, for answer equivalence purposes. */ + answer->exp.tokens[0].flags &= ~PREV_WHITE; - return 0; + answer->count = count; + *answer_ptr = answer; + + return true; } /* Parses an assertion directive of type TYPE, returning a pointer to the hash node of the predicate, or 0 on error. If an answer was - supplied, it is placed in ANSWERP, otherwise it is set to 0. */ + supplied, it is placed in EXP_PTR & EXP_COUNT, which is otherwise + set to 0. */ static cpp_hashnode * -parse_assertion (cpp_reader *pfile, struct answer **answerp, int type) +parse_assertion (cpp_reader *pfile, int type, cpp_macro **answer_ptr) { cpp_hashnode *result = 0; - const cpp_token *predicate; /* We don't expand predicates or answers. */ pfile->state.prevent_expansion++; - *answerp = 0; - predicate = cpp_get_token (pfile); + *answer_ptr = NULL; + + const cpp_token *predicate = cpp_get_token (pfile); if (predicate->type == CPP_EOF) cpp_error (pfile, CPP_DL_ERROR, "assertion without predicate"); else if (predicate->type != CPP_NAME) cpp_error_with_line (pfile, CPP_DL_ERROR, predicate->src_loc, 0, "predicate must be an identifier"); - else if (parse_answer (pfile, answerp, type, predicate->src_loc) == 0) + else if (parse_answer (pfile, type, predicate->src_loc, answer_ptr)) { unsigned int len = NODE_LEN (predicate->val.node.node); unsigned char *sym = (unsigned char *) alloca (len + 1); @@ -2255,25 +2248,27 @@ parse_assertion (cpp_reader *pfile, stru } pfile->state.prevent_expansion--; + return result; } /* Returns a pointer to the pointer to CANDIDATE in the answer chain, or a pointer to NULL if the answer is not in the chain. */ -static struct answer ** -find_answer (cpp_hashnode *node, const struct answer *candidate) +static cpp_macro ** +find_answer (cpp_hashnode *node, const cpp_macro *candidate) { unsigned int i; - struct answer **result; + cpp_macro **result = NULL; - for (result = &node->value.answers; *result; result = &(*result)->next) + for (result = &node->value.answers; *result; result = &(*result)->parm.next) { - struct answer *answer = *result; + cpp_macro *answer = *result; if (answer->count == candidate->count) { for (i = 0; i < answer->count; i++) - if (! _cpp_equiv_tokens (&answer->first[i], &candidate->first[i])) + if (!_cpp_equiv_tokens (&answer->exp.tokens[i], + &candidate->exp.tokens[i])) break; if (i == answer->count) @@ -2290,18 +2285,18 @@ find_answer (cpp_hashnode *node, const s int _cpp_test_assertion (cpp_reader *pfile, unsigned int *value) { - struct answer *answer; - cpp_hashnode *node; - - node = parse_assertion (pfile, &answer, T_IF); + cpp_macro *answer; + cpp_hashnode *node = parse_assertion (pfile, T_IF, &answer); /* For recovery, an erroneous assertion expression is handled as a failing assertion. */ *value = 0; if (node) - *value = (node->type == NT_ASSERTION && - (answer == 0 || *find_answer (node, answer) != 0)); + { + if (node->type == NT_ASSERTION) + *value = !answer || *find_answer (node, answer); + } else if (pfile->cur_token[-1].type == CPP_EOF) _cpp_backup_tokens (pfile, 1); @@ -2313,43 +2308,31 @@ _cpp_test_assertion (cpp_reader *pfile, static void do_assert (cpp_reader *pfile) { - struct answer *new_answer; - cpp_hashnode *node; + cpp_macro *answer; + cpp_hashnode *node = parse_assertion (pfile, T_ASSERT, &answer); - node = parse_assertion (pfile, &new_answer, T_ASSERT); if (node) { - size_t answer_size; - /* Place the new answer in the answer list. First check there is not a duplicate. */ - new_answer->next = 0; - if (node->type == NT_ASSERTION) + if (node->type == NT_ASSERTION && *find_answer (node, answer)) { - if (*find_answer (node, new_answer)) - { - cpp_error (pfile, CPP_DL_WARNING, "\"%s\" re-asserted", - NODE_NAME (node) + 1); - return; - } - new_answer->next = node->value.answers; + cpp_error (pfile, CPP_DL_WARNING, "\"%s\" re-asserted", + NODE_NAME (node) + 1); + return; } - answer_size = sizeof (struct answer) + ((new_answer->count - 1) - * sizeof (cpp_token)); - /* Commit or allocate storage for the object. */ - if (pfile->hash_table->alloc_subobject) - { - struct answer *temp_answer = new_answer; - new_answer = (struct answer *) pfile->hash_table->alloc_subobject - (answer_size); - memcpy (new_answer, temp_answer, answer_size); - } - else - BUFF_FRONT (pfile->a_buff) += answer_size; + /* Commit or allocate storage for the answer. */ + answer = (cpp_macro *)_cpp_commit_buff + (pfile, sizeof (cpp_macro) - sizeof (cpp_token) + + sizeof (cpp_token) * answer->count); + + if (node->type == NT_ASSERTION) + answer->parm.next = node->value.answers; node->type = NT_ASSERTION; - node->value.answers = new_answer; + node->value.answers = answer; + check_eol (pfile, false); } } @@ -2358,25 +2341,24 @@ do_assert (cpp_reader *pfile) static void do_unassert (cpp_reader *pfile) { - cpp_hashnode *node; - struct answer *answer; + cpp_macro *answer; + cpp_hashnode *node = parse_assertion (pfile, T_UNASSERT, &answer); - node = parse_assertion (pfile, &answer, T_UNASSERT); /* It isn't an error to #unassert something that isn't asserted. */ if (node && node->type == NT_ASSERTION) { if (answer) { - struct answer **p = find_answer (node, answer), *temp; + cpp_macro **p = find_answer (node, answer); - /* Remove the answer from the list. */ - temp = *p; - if (temp) - *p = temp->next; - - /* Did we free the last answer? */ - if (node->value.answers == 0) - node->type = NT_VOID; + /* Remove the assert from the list. */ + if (cpp_macro *temp = *p) + { + *p = temp->parm.next; + /* Did we free the last answer? */ + if (!*p) + node->type = NT_VOID; + } check_eol (pfile, false); } Index: libcpp/include/cpp-id-data.h =================================================================== --- libcpp/include/cpp-id-data.h (revision 263656) +++ libcpp/include/cpp-id-data.h (working copy) @@ -17,10 +17,3 @@ along with this program; see the file CO #include "cpplib.h" -/* Chained list of answers to an assertion. */ -struct GTY(()) answer { - struct answer *next; - unsigned int count; - cpp_token GTY ((length ("%h.count"))) first[1]; -}; - Index: libcpp/include/cpplib.h =================================================================== --- libcpp/include/cpplib.h (revision 263656) +++ libcpp/include/cpplib.h (working copy) @@ -36,7 +36,6 @@ typedef struct cpp_macro cpp_macro; typedef struct cpp_callbacks cpp_callbacks; typedef struct cpp_dir cpp_dir; -struct answer; struct _cpp_file; /* The first three groups, apart from '=', can appear in preprocessor @@ -674,25 +673,33 @@ struct cpp_dir /* The kind of the cpp_macro. */ enum cpp_macro_kind { cmk_macro, /* An ISO macro (token expansion). */ + cmk_assert, /* An assertion. */ cmk_traditional, /* A traditional macro (text expansion). */ }; /* Each macro definition is recorded in a cpp_macro structure. Variadic macros cannot occur with traditional cpp. */ struct GTY(()) cpp_macro { - /* Parameters, if any. If parameter names use extended identifiers, - the original spelling of those identifiers, not the canonical - UTF-8 spelling, goes here. */ - cpp_hashnode ** GTY ((nested_ptr (union tree_node, - "%h ? CPP_HASHNODE (GCC_IDENT_TO_HT_IDENT (%h)) : NULL", - "%h ? HT_IDENT_TO_GCC_IDENT (HT_NODE (%h)) : NULL"), - length ("%h.paramc"))) - params; + union cpp_parm_u + { + /* Parameters, if any. If parameter names use extended identifiers, + the original spelling of those identifiers, not the canonical + UTF-8 spelling, goes here. */ + cpp_hashnode ** GTY ((tag ("false"), + nested_ptr (union tree_node, + "%h ? CPP_HASHNODE (GCC_IDENT_TO_HT_IDENT (%h)) : NULL", + "%h ? HT_IDENT_TO_GCC_IDENT (HT_NODE (%h)) : NULL"), + length ("%1.paramc"))) params; + + /* If this is an assertion, the next one in the chain. */ + cpp_macro *GTY ((tag ("true"))) next; + } GTY ((desc ("%1.kind == cmk_assert"))) parm; /* Definition line number. */ source_location line; - /* Number of tokens in expansion, or bytes for traditional macros. */ + /* Number of tokens in body, or bytes for traditional macros. */ + /* Do we really need 2^32-1 range here? */ unsigned int count; /* Number of parameters. */ @@ -814,7 +821,7 @@ union GTY(()) _cpp_hashnode_value { /* If a macro. */ cpp_macro * GTY((tag ("NTV_MACRO"))) macro; /* Answers to an assertion. */ - struct answer * GTY ((tag ("NTV_ANSWER"))) answers; + cpp_macro * GTY ((tag ("NTV_ANSWER"))) answers; /* Code for a builtin macro. */ enum cpp_builtin_type GTY ((tag ("NTV_BUILTIN"))) builtin; /* Macro argument index. */ Index: libcpp/macro.c =================================================================== --- libcpp/macro.c (revision 263656) +++ libcpp/macro.c (working copy) @@ -3017,7 +3017,7 @@ warn_of_redefinition (cpp_reader *pfile, /* Check parameter spellings. */ for (i = 0; i < macro1->paramc; i++) - if (macro1->params[i] != macro2->params[i]) + if (macro1->parm.params[i] != macro2->parm.params[i]) return true; /* Check the replacement text or tokens. */ @@ -3326,7 +3326,7 @@ create_iso_definition (cpp_reader *pfile { macro->variadic = varadic; macro->paramc = nparms; - macro->params = params; + macro->parm.params = params; macro->fun_like = true; } else @@ -3472,7 +3472,7 @@ _cpp_new_macro (cpp_reader *pfile, cpp_m cpp_macro *macro = (cpp_macro *) placement; macro->line = pfile->directive_line; - macro->params = 0; + macro->parm.params = 0; macro->lazy = 0; macro->paramc = 0; macro->variadic = 0; @@ -3618,7 +3618,7 @@ check_trad_stringification (cpp_reader * identifier inside the string matches one of them. */ for (i = 0; i < macro->paramc; i++) { - const cpp_hashnode *node = macro->params[i]; + const cpp_hashnode *node = macro->parm.params[i]; if (NODE_LEN (node) == len && !memcmp (p, NODE_NAME (node), len)) @@ -3663,7 +3663,7 @@ cpp_macro_definition (cpp_reader *pfile, len += 4; /* "()" plus possible final ".." of named varargs (we have + 1 below). */ for (i = 0; i < macro->paramc; i++) - len += NODE_LEN (macro->params[i]) + 1; /* "," */ + len += NODE_LEN (macro->parm.params[i]) + 1; /* "," */ } /* This should match below where we fill in the buffer. */ @@ -3707,7 +3707,7 @@ cpp_macro_definition (cpp_reader *pfile, *buffer++ = '('; for (i = 0; i < macro->paramc; i++) { - cpp_hashnode *param = macro->params[i]; + cpp_hashnode *param = macro->parm.params[i]; if (param != pfile->spec_nodes.n__VA_ARGS__) { Index: libcpp/traditional.c =================================================================== --- libcpp/traditional.c (revision 263656) +++ libcpp/traditional.c (working copy) @@ -918,7 +918,7 @@ _cpp_replacement_text_len (const cpp_mac len += b->text_len; if (b->arg_index == 0) break; - len += NODE_LEN (macro->params[b->arg_index - 1]); + len += NODE_LEN (macro->parm.params[b->arg_index - 1]); exp += BLOCK_LEN (b->text_len); } } @@ -947,7 +947,7 @@ _cpp_copy_replacement_text (const cpp_ma dest += b->text_len; if (b->arg_index == 0) break; - param = macro->params[b->arg_index - 1]; + param = macro->parm.params[b->arg_index - 1]; memcpy (dest, NODE_NAME (param), NODE_LEN (param)); dest += NODE_LEN (param); exp += BLOCK_LEN (b->text_len); @@ -1210,7 +1210,7 @@ _cpp_create_trad_definition (cpp_reader { macro = _cpp_new_macro (pfile, cmk_traditional, _cpp_aligned_alloc (pfile, sizeof (cpp_macro))); - macro->params = params; + macro->parm.params = params; macro->paramc = nparms; macro->fun_like = fun_like != 0; }