diff mbox

__has_{,cpp_}attribute fixes (PR preprocessor/63831)

Message ID 20141205202855.GR1923@tucnak.redhat.com
State New
Headers show

Commit Message

Jakub Jelinek Dec. 5, 2014, 8:28 p.m. UTC
Hi!

This patch rewrites __has_attribute support, so that:
1) it is normal built-in macro, so it can be expanded even outside of
   #if (apparently clang supports that)
2) it is expanded properly even during preprocessing
3) there is no __has_attribute__ middle-end secondary macro,
   when it is a built-in macro, it works fine in #ifdef too
4) it is not expanded / does not ICE for -lang-asm preprocessing, or
   e.g. when preprocessing Fortran

Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?

2014-12-05  Jakub Jelinek  <jakub@redhat.com>

	PR preprocessor/63831
	* c-cppbuiltin.c (c_cpp_builtins): Don't define __has_attribute
	and __has_cpp_attribute here.
	* c-ppoutput.c (init_pp_output): Set cb->has_attribute to
	c_common_has_attribute.
	* c-common.h (c_common_has_attribute): New prototype.
	* c-lex.c (init_c_lex): Set cb->has_attribute to
	c_common_has_attribute instead of cb_has_attribute.
	(get_token_no_padding): New function.
	(cb_has_attribute): Renamed to ...
	(c_common_has_attribute): ... this.  No longer static.  Use
	get_token_no_padding, require ()s, don't build TREE_LIST
	unnecessarily, fix up formatting, adjust diagnostics, call
	init_attributes.

	* directives.c (lex_macro_node): Remove __has_attribute__ handling.
	* internal.h (struct spec_node): Remove n__has_attribute__ field.
	(struct lexer_state): Remove in__has_attribute__ field.
	* macro.c (_cpp_builtin_macro_text): Handle BT_HAS_ATTRIBUTE.
	* identifiers.c (_cpp_init_hashtable): Remove __has_attribute__
	handling.
	* init.c (builtin_array): Add __has_attribute and __has_cpp_attribute.
	(cpp_init_special_builtins): Don't initialize __has_attribute
	or __has_cpp_attribute if CLK_ASM or pfile->cb.has_attribute is NULL.
	* traditional.c (enum ls): Remove ls_has_attribute,
	ls_has_attribute_close.
	(_cpp_scan_out_logical_line): Remove __has_attribute__ handling.
	* include/cpplib.h (enum cpp_builtin_type): Add BT_HAS_ATTRIBUTE.
	* pch.c (cpp_read_state): Remove __has_attribute__ handling.
	* expr.c (eval_token): Likewise.
	(parse_has_attribute): Removed.

	* c-c++-common/cpp/pr63831-1.c: New test.
	* c-c++-common/cpp/pr63831-2.c: New test.


	Jakub

Comments

Jason Merrill Dec. 17, 2014, 9:14 p.m. UTC | #1
On 12/05/2014 03:28 PM, Jakub Jelinek wrote:
> 3) there is no __has_attribute__ middle-end secondary macro,
>    when it is a built-in macro, it works fine in #ifdef too

I'm not sure what the rationale for the secondary macro was.  Ed?

> -cb_has_attribute (cpp_reader *pfile)
> +c_common_has_attribute (cpp_reader *pfile)

Let's not change the name; it's still a lexer callback rather than a 
function to be called by C-family front ends.

OK with that change if Ed doesn't object in the next couple of days.

Jason
Jakub Jelinek Dec. 17, 2014, 10:43 p.m. UTC | #2
On Wed, Dec 17, 2014 at 04:14:00PM -0500, Jason Merrill wrote:
> On 12/05/2014 03:28 PM, Jakub Jelinek wrote:
> >3) there is no __has_attribute__ middle-end secondary macro,
> >   when it is a built-in macro, it works fine in #ifdef too
> 
> I'm not sure what the rationale for the secondary macro was.  Ed?

Can't speak for Ed of course, my understanding for the secondary
macro was that one should be able to use #ifdef __has_attribute
and the current trunk's __has_attribute__ is not a macro, just special
processing of a token in #if directives, similar to say defined(...),
so it couldn't be used easily in #ifdef (nor redefined etc.).

> >-cb_has_attribute (cpp_reader *pfile)
> >+c_common_has_attribute (cpp_reader *pfile)
> 
> Let's not change the name; it's still a lexer callback rather than a
> function to be called by C-family front ends.

Ok.

> OK with that change if Ed doesn't object in the next couple of days.

Will wait.

	Jakub
Ed Smith-Rowland Dec. 19, 2014, 12:09 p.m. UTC | #3
On 12/17/2014 05:43 PM, Jakub Jelinek wrote:
> On Wed, Dec 17, 2014 at 04:14:00PM -0500, Jason Merrill wrote:
>> On 12/05/2014 03:28 PM, Jakub Jelinek wrote:
>>> 3) there is no __has_attribute__ middle-end secondary macro,
>>>    when it is a built-in macro, it works fine in #ifdef too
>> I'm not sure what the rationale for the secondary macro was.  Ed?
> Can't speak for Ed of course, my understanding for the secondary
> macro was that one should be able to use #ifdef __has_attribute
> and the current trunk's __has_attribute__ is not a macro, just special
> processing of a token in #if directives, similar to say defined(...),
> so it couldn't be used easily in #ifdef (nor redefined etc.).
>
>>> -cb_has_attribute (cpp_reader *pfile)
>>> +c_common_has_attribute (cpp_reader *pfile)
>> Let's not change the name; it's still a lexer callback rather than a
>> function to be called by C-family front ends.
> Ok.
>
>> OK with that change if Ed doesn't object in the next couple of days.
> Will wait.
>
> 	Jakub
>
After a food fight involving building with jit I finally got around to 
building, testing, and playing with this patch.

I even did template tag dispatch - an abomination probably but it works ;-)

So I say go ahead with this one.

Thank you very much Jakub!

Ed
diff mbox

Patch

--- gcc/c-family/c-cppbuiltin.c.jj	2014-11-13 00:07:36.000000000 +0100
+++ gcc/c-family/c-cppbuiltin.c	2014-12-05 13:55:27.065734603 +0100
@@ -800,11 +800,6 @@  c_cpp_builtins (cpp_reader *pfile)
   cpp_define (pfile, "__has_include(STR)=__has_include__(STR)");
   cpp_define (pfile, "__has_include_next(STR)=__has_include_next__(STR)");
 
-  /* Set attribute test macros for all C/C++ (not for just C++11 etc.)
-     The builtin __has_attribute__ is defined in libcpp.  */
-  cpp_define (pfile, "__has_attribute(STR)=__has_attribute__(STR)");
-  cpp_define (pfile, "__has_cpp_attribute(STR)=__has_attribute__(STR)");
-
   if (c_dialect_cxx ())
     {
       if (flag_weak && SUPPORTS_ONE_ONLY)
--- gcc/c-family/c-ppoutput.c.jj	2014-08-01 09:23:33.000000000 +0200
+++ gcc/c-family/c-ppoutput.c	2014-12-05 12:18:57.372593264 +0100
@@ -151,6 +151,8 @@  init_pp_output (FILE *out_stream)
       cb->used_undef = cb_used_undef;
     }
 
+  cb->has_attribute = c_common_has_attribute;
+
   /* Initialize the print structure.  */
   print.src_line = 1;
   print.printed = 0;
--- gcc/c-family/c-common.h.jj	2014-11-21 10:23:58.000000000 +0100
+++ gcc/c-family/c-common.h	2014-12-05 10:28:12.182500519 +0100
@@ -959,6 +959,7 @@  extern void c_cpp_builtins_optimize_prag
 extern bool c_cpp_error (cpp_reader *, int, int, location_t, unsigned int,
 			 const char *, va_list *)
      ATTRIBUTE_GCC_DIAG(6,0);
+extern int c_common_has_attribute (cpp_reader *);
 
 extern bool parse_optimize_options (tree, bool);
 
--- gcc/c-family/c-lex.c.jj	2014-11-11 00:05:25.000000000 +0100
+++ gcc/c-family/c-lex.c	2014-12-05 14:22:17.402328011 +0100
@@ -64,7 +64,6 @@  static void cb_ident (cpp_reader *, unsi
 static void cb_def_pragma (cpp_reader *, unsigned int);
 static void cb_define (cpp_reader *, unsigned int, cpp_hashnode *);
 static void cb_undef (cpp_reader *, unsigned int, cpp_hashnode *);
-static int cb_has_attribute (cpp_reader *);
 
 void
 init_c_lex (void)
@@ -89,7 +88,7 @@  init_c_lex (void)
   cb->def_pragma = cb_def_pragma;
   cb->valid_pch = c_common_valid_pch;
   cb->read_pch = c_common_read_pch;
-  cb->has_attribute = cb_has_attribute;
+  cb->has_attribute = c_common_has_attribute;
 
   /* Set the debug callbacks if we can use them.  */
   if ((debug_info_level == DINFO_LEVEL_VERBOSE
@@ -288,57 +287,80 @@  cb_undef (cpp_reader * ARG_UNUSED (pfile
 			 (const char *) NODE_NAME (node));
 }
 
+/* Wrapper around cpp_get_token to skip CPP_PADDING tokens
+   and not consume CPP_EOF.  */
+static const cpp_token *
+get_token_no_padding (cpp_reader *pfile)
+{
+  for (;;)
+    {
+      const cpp_token *ret = cpp_peek_token (pfile, 0);
+      if (ret->type == CPP_EOF)
+	return ret;
+      ret = cpp_get_token (pfile);
+      if (ret->type != CPP_PADDING)
+	return ret;
+    }
+}
+
 /* Callback for has_attribute.  */
-static int
-cb_has_attribute (cpp_reader *pfile)
+int
+c_common_has_attribute (cpp_reader *pfile)
 {
   int result = 0;
-  bool paren = false;
-  tree attr_ns = NULL_TREE, attr_id = NULL_TREE, attr_name = NULL_TREE;
+  tree attr_name = NULL_TREE;
   const cpp_token *token;
 
-  token = cpp_get_token (pfile);
-  if (token->type == CPP_OPEN_PAREN)
+  token = get_token_no_padding (pfile);
+  if (token->type != CPP_OPEN_PAREN)
     {
-      paren = true;
-      token = cpp_get_token (pfile);
+      cpp_error (pfile, CPP_DL_ERROR,
+		 "missing '(' after \"__has_attribute\"");
+      return 0;
     }
-
+  token = get_token_no_padding (pfile);
   if (token->type == CPP_NAME)
     {
-      //node = token->val.node.node;
-      const cpp_token *nxt_token = cpp_peek_token (pfile, 0);
-      if (c_dialect_cxx() && nxt_token->type == CPP_SCOPE)
+      attr_name = get_identifier ((const char *)
+				  cpp_token_as_text (pfile, token));
+      if (c_dialect_cxx ())
 	{
-	  nxt_token = cpp_get_token (pfile); // Eat scope.
-	  nxt_token = cpp_get_token (pfile);
-	  if (nxt_token->type == CPP_NAME)
+	  int idx = 0;
+	  const cpp_token *nxt_token;
+	  do
+	    nxt_token = cpp_peek_token (pfile, idx++);
+	  while (nxt_token->type == CPP_PADDING);
+	  if (nxt_token->type == CPP_SCOPE)
 	    {
-	      attr_ns = get_identifier (
-			(const char *) cpp_token_as_text (pfile, token));
-	      attr_id = get_identifier (
-			(const char *) cpp_token_as_text (pfile, nxt_token));
-	      attr_name = build_tree_list (attr_ns, attr_id);
+	      get_token_no_padding (pfile); // Eat scope.
+	      nxt_token = get_token_no_padding (pfile);
+	      if (nxt_token->type == CPP_NAME)
+		{
+		  tree attr_ns = attr_name;
+		  tree attr_id
+		    = get_identifier ((const char *)
+				      cpp_token_as_text (pfile, nxt_token));
+		  attr_name = build_tree_list (attr_ns, attr_id);
+		}
+	      else
+		{
+		  cpp_error (pfile, CPP_DL_ERROR,
+			     "attribute identifier required after scope");
+		  attr_name = NULL_TREE;
+		}
 	    }
-	  else
-	    cpp_error (pfile, CPP_DL_ERROR,
-		       "attribute identifier required after scope");
-	}
-      else
-	{
-	  attr_ns = get_identifier ("gnu");
-	  attr_id = get_identifier (
-		    (const char *) cpp_token_as_text (pfile, token));
-	  attr_name = build_tree_list (attr_ns, attr_id);
 	}
       if (attr_name)
 	{
+	  init_attributes ();
 	  const struct attribute_spec *attr = lookup_attribute_spec (attr_name);
 	  if (attr)
 	    {
-	      if (is_attribute_p ("noreturn", TREE_VALUE (attr_name)))
+	      if (TREE_CODE (attr_name) == TREE_LIST)
+		attr_name = TREE_VALUE (attr_name);
+	      if (is_attribute_p ("noreturn", attr_name))
 		result = 200809;
-	      else if (is_attribute_p ("deprecated", TREE_VALUE (attr_name)))
+	      else if (is_attribute_p ("deprecated", attr_name))
 		result = 201309;
 	      else
 		result = 1;
@@ -346,16 +368,18 @@  cb_has_attribute (cpp_reader *pfile)
 	}
     }
   else
-    cpp_error (pfile, CPP_DL_ERROR,
-	       "operator \"__has_attribute__\" requires an identifier");
+    {
+      cpp_error (pfile, CPP_DL_ERROR,
+		 "macro \"__has_attribute\" requires an identifier");
+      return 0;
+    }
 
-  if (paren && cpp_get_token (pfile)->type != CPP_CLOSE_PAREN)
+  if (get_token_no_padding (pfile)->type != CPP_CLOSE_PAREN)
     cpp_error (pfile, CPP_DL_ERROR,
-	       "missing ')' after \"__has_attribute__\"");
+	       "missing ')' after \"__has_attribute\"");
 
   return result;
 }
-
 
 /* Read a token and return its type.  Fill *VALUE with its value, if
    applicable.  Fill *CPP_FLAGS with the token's flags, if it is
--- libcpp/directives.c.jj	2014-11-11 00:06:26.000000000 +0100
+++ libcpp/directives.c	2014-12-05 13:18:57.591321684 +0100
@@ -571,10 +571,6 @@  lex_macro_node (cpp_reader *pfile, bool
 	     || 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 (is_def_or_undef
-	    && node == pfile->spec_nodes.n__has_attribute__)
-	cpp_error (pfile, CPP_DL_ERROR,
-		   "\"__has_attribute__\" cannot be used as a macro name");
       else if (! (node->flags & NODE_POISONED))
 	return node;
     }
--- libcpp/internal.h.jj	2014-12-05 12:30:46.000000000 +0100
+++ libcpp/internal.h	2014-12-05 13:19:26.174818060 +0100
@@ -261,9 +261,6 @@  struct lexer_state
   /* Nonzero if in a __has_include__ or __has_include_next__ statement.  */
   unsigned char in__has_include__;
 
-  /* Nonzero if in a __has_attribute__ statement.  */
-  unsigned char in__has_attribute__;
-
   /* Nonzero if prevent_expansion is true only because output is
      being discarded.  */
   unsigned char discarding_output;
@@ -287,7 +284,6 @@  struct spec_nodes
   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 */
-  cpp_hashnode *n__has_attribute__;	/* __has_attribute__ operator */
 };
 
 typedef struct _cpp_line_note _cpp_line_note;
--- libcpp/macro.c.jj	2014-11-11 00:06:26.000000000 +0100
+++ libcpp/macro.c	2014-12-05 12:31:58.478914005 +0100
@@ -393,6 +393,10 @@  _cpp_builtin_macro_text (cpp_reader *pfi
 	    "__COUNTER__ expanded inside directive with -fdirectives-only");
       number = pfile->counter++;
       break;
+
+    case BT_HAS_ATTRIBUTE:
+      number = pfile->cb.has_attribute (pfile);
+      break;
     }
 
   if (result == NULL)
--- libcpp/identifiers.c.jj	2014-11-11 00:06:27.000000000 +0100
+++ libcpp/identifiers.c	2014-12-05 13:18:12.580114755 +0100
@@ -72,7 +72,6 @@  _cpp_init_hashtable (cpp_reader *pfile,
   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__"));
-  s->n__has_attribute__   = cpp_lookup (pfile, DSC("__has_attribute__"));
 }
 
 /* Tear down the identifier hash table.  */
--- libcpp/init.c.jj	2014-11-11 00:06:27.000000000 +0100
+++ libcpp/init.c	2014-12-05 13:59:14.305730544 +0100
@@ -380,6 +380,8 @@  static const struct builtin_macro builti
   B("__LINE__",		 BT_SPECLINE,      true),
   B("__INCLUDE_LEVEL__", BT_INCLUDE_LEVEL, true),
   B("__COUNTER__",	 BT_COUNTER,       true),
+  B("__has_attribute",	 BT_HAS_ATTRIBUTE, true),
+  B("__has_cpp_attribute", BT_HAS_ATTRIBUTE, 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),
@@ -460,6 +462,10 @@  cpp_init_special_builtins (cpp_reader *p
 
   for (b = builtin_array; b < builtin_array + n; b++)
     {
+      if (b->value == BT_HAS_ATTRIBUTE
+	  && (CPP_OPTION (pfile, lang) == CLK_ASM
+	      || pfile->cb.has_attribute == NULL))
+	continue;
       cpp_hashnode *hp = cpp_lookup (pfile, b->name, b->len);
       hp->type = NT_MACRO;
       hp->flags |= NODE_BUILTIN;
--- libcpp/traditional.c.jj	2014-11-11 00:06:27.000000000 +0100
+++ libcpp/traditional.c	2014-12-05 13:16:51.991534677 +0100
@@ -76,9 +76,7 @@  enum ls {ls_none = 0,		/* Normal state.
 	 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_has_attribute,	/* After __has_attribute__.  */
-	 ls_has_attribute_close}; /* Looking for ')' of __has_attribute__.  */
+	 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.  */
@@ -535,12 +533,6 @@  _cpp_scan_out_logical_line (cpp_reader *
 		  lex_state = ls_has_include;
 		  continue;
 		}
-	      else if (pfile->state.in_expression
-		       && node == pfile->spec_nodes.n__has_attribute__)
-		{
-		  lex_state = ls_has_attribute;
-		  continue;
-		}
 	    }
 	  break;
 
@@ -566,8 +558,6 @@  _cpp_scan_out_logical_line (cpp_reader *
 		lex_state = ls_defined_close;
 	      else if (lex_state == ls_has_include)
 		lex_state = ls_has_include_close;
-	      else if (lex_state == ls_has_attribute)
-		lex_state = ls_has_attribute_close;
 	    }
 	  break;
 
@@ -606,8 +596,7 @@  _cpp_scan_out_logical_line (cpp_reader *
 		    }
 		}
 	      else if (lex_state == ls_answer || lex_state == ls_defined_close
-			|| lex_state == ls_has_include_close
-			|| lex_state == ls_has_attribute_close)
+			|| lex_state == ls_has_include_close)
 		lex_state = ls_none;
 	    }
 	  break;
@@ -689,8 +678,7 @@  _cpp_scan_out_logical_line (cpp_reader *
       else if (lex_state == ls_hash
 	       || lex_state == ls_predicate
 	       || lex_state == ls_defined
-	       || lex_state == ls_has_include
-	       || lex_state == ls_has_attribute)
+	       || lex_state == ls_has_include)
 	lex_state = ls_none;
 
       /* ls_answer and ls_defined_close keep going until ')'.  */
--- libcpp/include/cpplib.h.jj	2014-11-11 00:06:26.000000000 +0100
+++ libcpp/include/cpplib.h	2014-12-05 11:11:55.381684210 +0100
@@ -676,6 +676,7 @@  enum cpp_builtin_type
   BT_PRAGMA,			/* `_Pragma' operator */
   BT_TIMESTAMP,			/* `__TIMESTAMP__' */
   BT_COUNTER,			/* `__COUNTER__' */
+  BT_HAS_ATTRIBUTE,		/* `__has_attribute__(x)' */
   BT_FIRST_USER,		/* User defined builtin macros.  */
   BT_LAST_USER = BT_FIRST_USER + 31
 };
--- libcpp/pch.c.jj	2014-11-11 00:06:27.000000000 +0100
+++ libcpp/pch.c	2014-12-05 13:17:51.217491151 +0100
@@ -835,7 +835,6 @@  cpp_read_state (cpp_reader *r, const cha
     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__"));
-    s->n__has_attribute__ = cpp_lookup (r, DSC("__has_attribute__"));
   }
 
   old_state = r->state;
--- libcpp/expr.c.jj	2014-11-11 00:06:27.000000000 +0100
+++ libcpp/expr.c	2014-12-05 13:15:22.823105568 +0100
@@ -65,7 +65,6 @@  static unsigned int interpret_int_suffix
 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_attribute (cpp_reader *);
 
 /* Token type abuse to create unary plus and minus operators.  */
 #define CPP_UPLUS ((enum cpp_ttype) (CPP_LAST_CPP_OP + 1))
@@ -1055,8 +1054,6 @@  eval_token (cpp_reader *pfile, const cpp
 	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_attribute__)
-	return parse_has_attribute (pfile);
       else if (CPP_OPTION (pfile, cplusplus)
 	       && (token->val.node.node == pfile->spec_nodes.n_true
 		   || token->val.node.node == pfile->spec_nodes.n_false))
@@ -2150,21 +2147,3 @@  parse_has_include (cpp_reader *pfile, en
 
   return result;
 }
-
-/* Handle meeting "__has_attribute__" in a preprocessor expression.  */
-static cpp_num
-parse_has_attribute (cpp_reader *pfile)
-{
-  pfile->state.in__has_attribute__++;
-
-  cpp_num result;
-  result.unsignedp = false;
-  result.high = 0;
-  result.overflow = false;
-
-  result.low = pfile->cb.has_attribute (pfile);
-
-  pfile->state.in__has_attribute__--;
-
-  return result;
-}
--- gcc/testsuite/c-c++-common/cpp/pr63831-1.c.jj	2014-12-05 14:10:55.256362265 +0100
+++ gcc/testsuite/c-c++-common/cpp/pr63831-1.c	2014-12-05 14:28:34.958668282 +0100
@@ -0,0 +1,64 @@ 
+/* PR preprocessor/63831 */
+/* { dg-do compile } */
+
+#ifdef __has_attribute
+typedef char T1[__has_attribute (__noreturn__) == 200809 ? 1 : -1];
+typedef char T2[__has_attribute (alloc_size) == 1 ? 1 : -1];
+typedef char T3[__has_attribute (non_existent_attribuuuute) == 0 ? 1 : -1];
+#endif
+#if __has_attribute (noreturn) == 200809
+typedef char T4;
+#endif
+#define d deprecated
+typedef char T5[__has_attribute (d) == 201309 ? 1 : -1];
+T1 t1;
+T2 t2;
+T3 t3;
+T4 t4;
+T5 t5;
+#ifdef __cplusplus
+typedef char T6[__has_attribute (gnu::__noreturn__) == 200809 ? 1 : -1];
+typedef char T7[__has_attribute (gnu::alloc_size) == 1 ? 1 : -1];
+typedef char T8[__has_attribute (gnu::non_existent_attribuuuute) == 0 ? 1 : -1];
+#if __has_attribute (gnu::noreturn) == 200809
+typedef char T9;
+#endif
+#define d2 gnu::deprecated
+typedef char T10[__has_attribute (d) == 201309 ? 1 : -1];
+T6 t6;
+T7 t7;
+T8 t8;
+T9 t9;
+T10 t10;
+#endif
+#ifdef __has_cpp_attribute
+typedef char T11[__has_cpp_attribute (__noreturn__) == 200809 ? 1 : -1];
+typedef char T12[__has_cpp_attribute (alloc_size) == 1 ? 1 : -1];
+typedef char T13[__has_cpp_attribute (non_existent_attribuuuute) == 0 ? 1 : -1];
+#endif
+#if __has_cpp_attribute (noreturn) == 200809
+typedef char T14;
+#endif
+#define d deprecated
+typedef char T15[__has_cpp_attribute (d) == 201309 ? 1 : -1];
+T11 t11;
+T12 t12;
+T13 t13;
+T14 t14;
+T15 t15;
+#ifdef __cplusplus
+typedef char T16[__has_cpp_attribute (gnu::__noreturn__) == 200809 ? 1 : -1];
+typedef char T17[__has_cpp_attribute (gnu::alloc_size) == 1 ? 1 : -1];
+typedef char T18[__has_cpp_attribute (gnu::non_existent_attribuuuute) == 0 ? 1 : -1];
+#if __has_cpp_attribute (gnu::noreturn) == 200809
+typedef char T19;
+#endif
+#define d2 gnu::deprecated
+typedef char T20[__has_cpp_attribute (d) == 201309 ? 1 : -1];
+T16 t16;
+T17 t17;
+T18 t18;
+T19 t19;
+T20 t20;
+#endif
+int t21 = __has_attribute (noreturn) + __has_cpp_attribute (__malloc__);
--- gcc/testsuite/c-c++-common/cpp/pr63831-2.c.jj	2014-12-05 14:29:49.010362082 +0100
+++ gcc/testsuite/c-c++-common/cpp/pr63831-2.c	2014-12-05 14:29:44.687438334 +0100
@@ -0,0 +1,7 @@ 
+/* PR preprocessor/63831 */
+/* { dg-do compile } */
+/* { dg-options "-save-temps" } */
+
+#include "pr63831-1.c"
+
+/* { dg-final { cleanup-saved-temps } } */