diff mbox series

#assert becomes macro-like

Message ID 606feb9a-fa6c-6023-3d8c-9b8ca4211713@acm.org
State New
Headers show
Series #assert becomes macro-like | expand

Commit Message

Nathan Sidwell Aug. 20, 2018, 12:38 p.m. UTC
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
diff mbox series

Patch

2018-08-20  Nathan Sidwell  <nathan@acm.org>

	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;
     }