aboutsummaryrefslogtreecommitdiff
path: root/gcc/c/c-parser.cc
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/c/c-parser.cc')
-rw-r--r--gcc/c/c-parser.cc85
1 files changed, 84 insertions, 1 deletions
diff --git a/gcc/c/c-parser.cc b/gcc/c/c-parser.cc
index 195cace..88dd0be 100644
--- a/gcc/c/c-parser.cc
+++ b/gcc/c/c-parser.cc
@@ -74,6 +74,8 @@ along with GCC; see the file COPYING3. If not see
#include "bitmap.h"
#include "analyzer/analyzer-language.h"
#include "toplev.h"
+#include "asan.h"
+#include "c-family/c-ubsan.h"
/* We need to walk over decls with incomplete struct/union/enum types
after parsing the whole translation unit.
@@ -12262,12 +12264,15 @@ c_parser_postfix_expression (c_parser *parser)
C_BUILTIN_STDC_HAS_SINGLE_BIT,
C_BUILTIN_STDC_LEADING_ONES,
C_BUILTIN_STDC_LEADING_ZEROS,
+ C_BUILTIN_STDC_ROTATE_LEFT,
+ C_BUILTIN_STDC_ROTATE_RIGHT,
C_BUILTIN_STDC_TRAILING_ONES,
C_BUILTIN_STDC_TRAILING_ZEROS,
C_BUILTIN_STDC_MAX
} stdc_rid = C_BUILTIN_STDC_MAX;
const char *name
= IDENTIFIER_POINTER (c_parser_peek_token (parser)->value);
+ unsigned num_args = 1;
switch (name[sizeof ("__builtin_stdc_") - 1])
{
case 'b':
@@ -12316,6 +12321,13 @@ c_parser_postfix_expression (c_parser *parser)
else
stdc_rid = C_BUILTIN_STDC_LEADING_ZEROS;
break;
+ case 'r':
+ if (name[sizeof ("__builtin_stdc_rotate_") - 1] == 'l')
+ stdc_rid = C_BUILTIN_STDC_ROTATE_LEFT;
+ else
+ stdc_rid = C_BUILTIN_STDC_ROTATE_RIGHT;
+ num_args = 2;
+ break;
case 't':
if (name[sizeof ("__builtin_stdc_trailing_") - 1] == 'o')
stdc_rid = C_BUILTIN_STDC_TRAILING_ONES;
@@ -12334,7 +12346,7 @@ c_parser_postfix_expression (c_parser *parser)
break;
}
- if (vec_safe_length (cexpr_list) != 1)
+ if (vec_safe_length (cexpr_list) != num_args)
{
error_at (loc, "wrong number of arguments to %qs", name);
expr.set_error ();
@@ -12406,6 +12418,77 @@ c_parser_postfix_expression (c_parser *parser)
without evaluating arg multiple times, type being
__typeof (arg) and prec __builtin_popcountg ((type) ~0)). */
int prec = TYPE_PRECISION (type);
+ if (num_args == 2)
+ {
+ /* Expand:
+ __builtin_stdc_rotate_left (arg1, arg2) as
+ arg1 r<< (arg2 % prec)
+ __builtin_stdc_rotate_right (arg1, arg2) as
+ arg1 r>> (arg2 % prec). */
+ arg_p = &(*cexpr_list)[1];
+ *arg_p = convert_lvalue_to_rvalue (loc, *arg_p, true, true);
+ if (!INTEGRAL_TYPE_P (TREE_TYPE (arg_p->value)))
+ {
+ error_at (loc, "%qs operand not an integral type", name);
+ expr.set_error ();
+ break;
+ }
+ if (TREE_CODE (TREE_TYPE (arg_p->value)) == ENUMERAL_TYPE)
+ {
+ error_at (loc, "argument %u in call to function "
+ "%qs has enumerated type", 2, name);
+ expr.set_error ();
+ break;
+ }
+ tree arg1 = save_expr (arg);
+ tree arg2 = save_expr (arg_p->value);
+ tree_code code;
+ if (stdc_rid == C_BUILTIN_STDC_ROTATE_LEFT)
+ code = LROTATE_EXPR;
+ else
+ code = RROTATE_EXPR;
+
+ if (TREE_CODE (arg2) == INTEGER_CST
+ && tree_int_cst_sgn (arg2) < 0)
+ warning_at (loc, OPT_Wshift_count_negative,
+ "rotate count is negative");
+
+ tree instrument_expr = NULL_TREE;
+ if (sanitize_flags_p (SANITIZE_SHIFT))
+ instrument_expr = ubsan_instrument_shift (loc, code,
+ arg1, arg2);
+
+ /* Promote arg2 to unsigned just so that we don't
+ need to deal with arg2 type not being able to represent
+ prec. In the end gimplification uses unsigned int
+ for all shifts/rotates anyway. */
+ if (TYPE_PRECISION (TREE_TYPE (arg2))
+ < TYPE_PRECISION (integer_type_node))
+ arg2 = fold_convert (unsigned_type_node, arg2);
+
+ if (TYPE_UNSIGNED (TREE_TYPE (arg2)))
+ arg2 = build2_loc (loc, TRUNC_MOD_EXPR, TREE_TYPE (arg2),
+ arg2, build_int_cst (TREE_TYPE (arg2),
+ prec));
+ else
+ {
+ /* When second argument is signed, just do the modulo in
+ unsigned type, that results in better generated code
+ (for power of 2 precisions bitwise AND). */
+ tree utype = c_common_unsigned_type (TREE_TYPE (arg2));
+ arg2 = build2_loc (loc, TRUNC_MOD_EXPR, utype,
+ fold_convert (utype, arg2),
+ build_int_cst (utype, prec));
+ }
+
+ expr.value = build2_loc (loc, code, TREE_TYPE (arg1), arg1,
+ arg2);
+ if (instrument_expr)
+ expr.value = build2_loc (loc, COMPOUND_EXPR,
+ TREE_TYPE (expr.value),
+ instrument_expr, expr.value);
+ break;
+ }
tree barg1 = arg;
switch (stdc_rid)
{