Wolfgang Thallergcc16 merge934c3885 months agoHistory
2423 lines · 66.3 KB · C++
RawDownload
/* Parse C expressions for cpplib.   Copyright (C) 1987-2026 Free Software Foundation, Inc.   Contributed by Per Bothner, 1994. This program is free software; you can redistribute it and/or modify itunder the terms of the GNU General Public License as published by theFree Software Foundation; either version 3, or (at your option) anylater version. This program is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY; without even the implied warranty ofMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See theGNU General Public License for more details. You should have received a copy of the GNU General Public Licensealong with this program; see the file COPYING3.  If not see<http://www.gnu.org/licenses/>.  */ #include "config.h"#include "system.h"#include "cpplib.h"#include "internal.h" #define PART_PRECISION (sizeof (cpp_num_part) * CHAR_BIT)#define HALF_MASK (~(cpp_num_part) 0 >> (PART_PRECISION / 2))#define LOW_PART(num_part) (num_part & HALF_MASK)#define HIGH_PART(num_part) (num_part >> (PART_PRECISION / 2)) struct op{  const cpp_token *token;	/* The token forming op (for diagnostics).  */  cpp_num value;		/* The value logically "right" of op.  */  location_t loc;          /* The location of this value.         */  enum cpp_ttype op;}; /* Some simple utility routines on double integers.  */#define num_zerop(num) ((num.low | num.high) == 0)#define num_eq(num1, num2) (num1.low == num2.low && num1.high == num2.high)static bool num_positive (cpp_num, size_t);static bool num_greater_eq (cpp_num, cpp_num, size_t);static cpp_num num_trim (cpp_num, size_t);static cpp_num num_part_mul (cpp_num_part, cpp_num_part); static cpp_num num_unary_op (cpp_reader *, cpp_num, enum cpp_ttype);static cpp_num num_binary_op (cpp_reader *, cpp_num, cpp_num, enum cpp_ttype);static cpp_num num_negate (cpp_num, size_t);static cpp_num num_bitwise_op (cpp_reader *, cpp_num, cpp_num, enum cpp_ttype);static cpp_num num_inequality_op (cpp_reader *, cpp_num, cpp_num,				  enum cpp_ttype);static cpp_num num_equality_op (cpp_reader *, cpp_num, cpp_num,				enum cpp_ttype);static cpp_num num_mul (cpp_reader *, cpp_num, cpp_num);static cpp_num num_div_op (cpp_reader *, cpp_num, cpp_num, enum cpp_ttype,			   location_t);static cpp_num num_lshift (cpp_reader *, cpp_num, size_t, size_t);static cpp_num num_rshift (cpp_num, size_t, size_t); static cpp_num append_digit (cpp_num, int, int, size_t);static cpp_num parse_defined (cpp_reader *);static cpp_num eval_token (cpp_reader *, const cpp_token *, location_t);static struct op *reduce (cpp_reader *, struct op *, enum cpp_ttype);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 *); /* 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)) /* With -O2, gcc appears to produce nice code, moving the error   message load and subsequent jump completely out of the main path.  */#define SYNTAX_ERROR(msgid) \  do { cpp_error (pfile, CPP_DL_ERROR, msgid); goto syntax_error; } while(0)#define SYNTAX_ERROR2(msgid, arg) \  do { cpp_error (pfile, CPP_DL_ERROR, msgid, arg); goto syntax_error; } \  while(0)#define SYNTAX_ERROR_AT(loc, msgid) \  do { cpp_error_with_line (pfile, CPP_DL_ERROR, (loc), 0, msgid); goto syntax_error; } \  while(0)#define SYNTAX_ERROR2_AT(loc, msgid, arg)					\  do { cpp_error_with_line (pfile, CPP_DL_ERROR, (loc), 0, msgid, arg); goto syntax_error; } \  while(0) /* Subroutine of cpp_classify_number.  S points to a float suffix of   length LEN, possibly zero.  Returns 0 for an invalid suffix, or a   flag vector (of CPP_N_* bits) describing the suffix.  */static unsigned intinterpret_float_suffix (cpp_reader *pfile, const uchar *s, size_t len){  size_t orig_len = len;  const uchar *orig_s = s;  size_t flags;  size_t f, d, l, w, q, i, fn, fnx, fn_bits, bf16;   flags = 0;  f = d = l = w = q = i = fn = fnx = fn_bits = bf16 = 0;   /* The following decimal float suffixes, from TR 24732:2009, TS     18661-2:2015 and C23, are supported:      df, DF, d32, D32 - _Decimal32.     dd, DD, d64, D64 - _Decimal64.     dl, DL, d128, D128 - _Decimal128.     d64x, D64x - _Decimal64x.      Fixed-point suffixes, from TR 18037:2008, are supported.  They     consist of three parts, in order:      (i) An optional u or U, for unsigned types.      (ii) An optional h or H, for short types, or l or L, for long     types, or ll or LL, for long long types.  Use of ll or LL is a     GNU extension.      (iii) r or R, for _Fract types, or k or K, for _Accum types.      Otherwise the suffix is for a binary or standard floating-point     type.  Such a suffix, or the absence of a suffix, may be preceded     or followed by i, I, j or J, to indicate an imaginary number with     the corresponding complex type.  The following suffixes for     binary or standard floating-point types are supported:      f, F - float (ISO C and C++).     l, L - long double (ISO C and C++).     d, D - double, even with the FLOAT_CONST_DECIMAL64 pragma in	    operation (from TR 24732:2009; the pragma and the suffix	    are not included in TS 18661-2:2015).     w, W - machine-specific type such as __float80 (GNU extension).     q, Q - machine-specific type such as __float128 (GNU extension).     fN, FN - _FloatN (TS 18661-3:2015).     fNx, FNx - _FloatNx (TS 18661-3:2015).     bf16, BF16 - std::bfloat16_t (ISO C++23).  */   /* Process decimal float suffixes, which are two letters starting     with d or D.  Order and case are significant.  */  if (len == 2 && (*s == 'd' || *s == 'D'))    {      bool uppercase = (*s == 'D');      switch (s[1])      {      case 'f': return (!uppercase ? (CPP_N_DFLOAT | CPP_N_SMALL) : 0); break;      case 'F': return (uppercase ? (CPP_N_DFLOAT | CPP_N_SMALL) : 0); break;      case 'd': return (!uppercase ? (CPP_N_DFLOAT | CPP_N_MEDIUM) : 0); break;      case 'D': return (uppercase ? (CPP_N_DFLOAT | CPP_N_MEDIUM) : 0); break;      case 'l': return (!uppercase ? (CPP_N_DFLOAT | CPP_N_LARGE) : 0); break;      case 'L': return (uppercase ? (CPP_N_DFLOAT | CPP_N_LARGE) : 0); break;      default:	/* Additional two-character suffixes beginning with D are not	   for decimal float constants.  */	break;      }    }   if (CPP_OPTION (pfile, ext_numeric_literals))    {      /* Recognize a fixed-point suffix.  */      if (len != 0)	switch (s[len-1])	  {	  case 'k': case 'K': flags = CPP_N_ACCUM; break;	  case 'r': case 'R': flags = CPP_N_FRACT; break;	  default: break;	  }       /* Continue processing a fixed-point suffix.  The suffix is case	 insensitive except for ll or LL.  Order is significant.  */      if (flags)	{	  if (len == 1)	    return flags;	  len--; 	  if (*s == 'u' || *s == 'U')	    {	      flags |= CPP_N_UNSIGNED;	      if (len == 1)		return flags;	      len--;	      s++;            } 	  switch (*s)	  {	  case 'h': case 'H':	    if (len == 1)	      return flags |= CPP_N_SMALL;	    break;	  case 'l':	    if (len == 1)	      return flags |= CPP_N_MEDIUM;	    if (len == 2 && s[1] == 'l')	      return flags |= CPP_N_LARGE;	    break;	  case 'L':	    if (len == 1)	      return flags |= CPP_N_MEDIUM;	    if (len == 2 && s[1] == 'L')	      return flags |= CPP_N_LARGE;	    break;	  default:	    break;	  }	  /* Anything left at this point is invalid.  */	  return 0;	}    }   /* In any remaining valid suffix, the case and order don't matter.  */  while (len--)    {      switch (s[0])	{	case 'f': case 'F':	  f++;	  if (len > 0	      && s[1] >= '1'	      && s[1] <= '9'	      && fn_bits == 0)	    {	      f--;	      while (len > 0		     && s[1] >= '0'		     && s[1] <= '9'		     && fn_bits < CPP_FLOATN_MAX)		{		  fn_bits = fn_bits * 10 + (s[1] - '0');		  len--;		  s++;		}	      if (len > 0 && s[1] == 'x')		{		  fnx++;		  len--;		  s++;		}	      else		fn++;	    }	  break;	case 'b': case 'B':	  if (len > 2	      /* Except for bf16 / BF16 where case is significant.  */	      && s[1] == (s[0] == 'b' ? 'f' : 'F')	      && s[2] == '1'	      && s[3] == '6')	    {	      bf16++;	      len -= 3;	      s += 3;	      break;	    }	  return 0;	case 'd': case 'D':	  if (!CPP_OPTION (pfile, cplusplus) && orig_s == s && len > 1)	    {	      if (s[1] == '3' && s[2] == '2' && len == 2)		return CPP_N_DFLOAT | CPP_N_SMALL;	      if (s[1] == '6' && s[2] == '4')		{		  if (len == 2)		    return CPP_N_DFLOAT | CPP_N_MEDIUM;		  if (len == 3 && s[3] == 'x')		    return CPP_N_DFLOAT | CPP_N_FLOATNX;		}	      if (s[1] == '1' && s[2] == '2' && len == 3 && s[3] == '8')		return CPP_N_DFLOAT | CPP_N_LARGE;	    }	  d++;	  break;	case 'l': case 'L': l++; break;	case 'w': case 'W': w++; break;	case 'q': case 'Q': q++; break;	case 'i': case 'I':	case 'j': case 'J': i++; break;	default:	  return 0;	}      s++;    }   /* Reject any case of multiple suffixes specifying types, multiple     suffixes specifying an imaginary constant, _FloatN or _FloatNx     suffixes for invalid values of N, and _FloatN suffixes for values     of N larger than can be represented in the return value.  The     caller is responsible for rejecting _FloatN suffixes where     _FloatN is not supported on the chosen target.  */  if (f + d + l + w + q + fn + fnx + bf16 > 1 || i > 1)    return 0;  if (fn_bits > CPP_FLOATN_MAX)    return 0;  if (fnx && fn_bits != 32 && fn_bits != 64 && fn_bits != 128)    return 0;  if (fn && fn_bits != 16 && fn_bits % 32 != 0)    return 0;  if (fn && fn_bits == 96)    return 0;   if (i)    {      if (!CPP_OPTION (pfile, ext_numeric_literals))	return 0;       /* In C++14 and up these suffixes are in the standard library, so treat	 them as user-defined literals.  */      if (CPP_OPTION (pfile, cplusplus)	  && CPP_OPTION (pfile, lang) > CLK_CXX11	  && orig_s[0] == 'i'	  && (orig_len == 1	      || (orig_len == 2		  && (orig_s[1] == 'f' || orig_s[1] == 'l'))))	return 0;    }   if ((w || q) && !CPP_OPTION (pfile, ext_numeric_literals))    return 0;   return ((i ? CPP_N_IMAGINARY : 0)	  | (f ? CPP_N_SMALL :	     d ? CPP_N_MEDIUM :	     l ? CPP_N_LARGE :	     w ? CPP_N_MD_W :	     q ? CPP_N_MD_Q :	     fn ? CPP_N_FLOATN | (fn_bits << CPP_FLOATN_SHIFT) :	     fnx ? CPP_N_FLOATNX | (fn_bits << CPP_FLOATN_SHIFT) :	     bf16 ? CPP_N_BFLOAT16 :	     CPP_N_DEFAULT));} /* Return the classification flags for a float suffix.  */unsigned intcpp_interpret_float_suffix (cpp_reader *pfile, const char *s, size_t len){  return interpret_float_suffix (pfile, (const unsigned char *)s, len);} /* Subroutine of cpp_classify_number.  S points to an integer suffix   of length LEN, possibly zero. Returns 0 for an invalid suffix, or a   flag vector describing the suffix.  */static unsigned intinterpret_int_suffix (cpp_reader *pfile, const uchar *s, size_t len){  size_t orig_len = len;  size_t u, l, i, z, wb;   u = l = i = z = wb = 0;   while (len--)    switch (s[len])      {      case 'z': case 'Z':	z++; break;      case 'u': case 'U':	u++; break;      case 'i': case 'I':      case 'j': case 'J':	i++; break;      case 'l': case 'L':	l++;	/* If there are two Ls, they must be adjacent and the same case.  */	if (l == 2 && s[len] != s[len + 1])	  return 0;	break;      case 'b':	if (len == 0 || s[len - 1] != 'w')	  return 0;	wb++;	len--;	break;      case 'B':	if (len == 0 || s[len - 1] != 'W')	  return 0;	wb++;	len--;	break;      default:	return 0;      }   if (l > 2 || u > 1 || i > 1 || z > 1 || wb > 1)    return 0;   if (z)    {      if (l > 0 || i > 0)	return 0;      if (!CPP_OPTION (pfile, cplusplus))	return 0;    }   if (wb)    {      if (CPP_OPTION (pfile, cplusplus))	return 0;      if (l > 0 || i > 0 || z > 0)	return 0;    }   if (i)    {      if (!CPP_OPTION (pfile, ext_numeric_literals))	return 0;       /* In C++14 and up these suffixes are in the standard library, so treat	 them as user-defined literals.  */      if (CPP_OPTION (pfile, cplusplus)	  && CPP_OPTION (pfile, lang) > CLK_CXX11	  && s[0] == 'i'	  && (orig_len == 1 || (orig_len == 2 && s[1] == 'l')))	return 0;    }   return ((i ? CPP_N_IMAGINARY : 0)	  | (u ? CPP_N_UNSIGNED : 0)	  | ((l == 0) ? CPP_N_SMALL	     : (l == 1) ? CPP_N_MEDIUM : CPP_N_LARGE)	  | (z ? CPP_N_SIZE_T : 0)	  | (wb ? CPP_N_BITINT : 0));} /* Return the classification flags for an int suffix.  */unsigned intcpp_interpret_int_suffix (cpp_reader *pfile, const char *s, size_t len){  return interpret_int_suffix (pfile, (const unsigned char *)s, len);} /* Return the string type corresponding to the the input user-defined string   literal type.  If the input type is not a user-defined string literal   type return the input type.  */enum cpp_ttypecpp_userdef_string_remove_type (enum cpp_ttype type){  if (type == CPP_STRING_USERDEF)    return CPP_STRING;  else if (type == CPP_WSTRING_USERDEF)    return CPP_WSTRING;  else if (type == CPP_STRING16_USERDEF)    return CPP_STRING16;  else if (type == CPP_STRING32_USERDEF)    return CPP_STRING32;  else if (type == CPP_UTF8STRING_USERDEF)    return CPP_UTF8STRING;  else    return type;} /* Return the user-defined string literal type corresponding to the input   string type.  If the input type is not a string type return the input   type.  */enum cpp_ttypecpp_userdef_string_add_type (enum cpp_ttype type){  if (type == CPP_STRING)    return CPP_STRING_USERDEF;  else if (type == CPP_WSTRING)    return CPP_WSTRING_USERDEF;  else if (type == CPP_STRING16)    return CPP_STRING16_USERDEF;  else if (type == CPP_STRING32)    return CPP_STRING32_USERDEF;  else if (type == CPP_UTF8STRING)    return CPP_UTF8STRING_USERDEF;  else    return type;} /* Return the char type corresponding to the the input user-defined char   literal type.  If the input type is not a user-defined char literal   type return the input type.  */enum cpp_ttypecpp_userdef_char_remove_type (enum cpp_ttype type){  if (type == CPP_CHAR_USERDEF)    return CPP_CHAR;  else if (type == CPP_WCHAR_USERDEF)    return CPP_WCHAR;  else if (type == CPP_CHAR16_USERDEF)    return CPP_CHAR16;  else if (type == CPP_CHAR32_USERDEF)    return CPP_CHAR32;  else if (type == CPP_UTF8CHAR_USERDEF)    return CPP_UTF8CHAR;  else    return type;} /* Return the user-defined char literal type corresponding to the input   char type.  If the input type is not a char type return the input   type.  */enum cpp_ttypecpp_userdef_char_add_type (enum cpp_ttype type){  if (type == CPP_CHAR)    return CPP_CHAR_USERDEF;  else if (type == CPP_WCHAR)    return CPP_WCHAR_USERDEF;  else if (type == CPP_CHAR16)    return CPP_CHAR16_USERDEF;  else if (type == CPP_CHAR32)    return CPP_CHAR32_USERDEF;  else if (type == CPP_UTF8CHAR)    return CPP_UTF8CHAR_USERDEF;  else

Lines 1–500 of 2423.

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t