@@ -477,6 +477,7 @@ USER_H = $(srcdir)/ginclude/float.h \
$(srcdir)/ginclude/stdalign.h \
$(srcdir)/ginclude/stdatomic.h \
$(srcdir)/ginclude/stdckdint.h \
+ $(srcdir)/ginclude/stdlength.h \
$(EXTRA_HEADERS)
USER_H_INC_NEXT_PRE = @user_headers_inc_next_pre@
@@ -407,6 +407,7 @@ const struct c_common_resword c_common_reswords[] =
{ "_Decimal64", RID_DFLOAT64, D_CONLY },
{ "_Decimal128", RID_DFLOAT128, D_CONLY },
{ "_Fract", RID_FRACT, D_CONLY | D_EXT },
+ { "_Lengthof", RID_LENGTHOF, D_CONLY | D_EXT },
{ "_Accum", RID_ACCUM, D_CONLY | D_EXT },
{ "_Sat", RID_SAT, D_CONLY | D_EXT },
{ "_Static_assert", RID_STATIC_ASSERT, D_CONLY },
@@ -523,6 +524,7 @@ const struct c_common_resword c_common_reswords[] =
{ "if", RID_IF, 0 },
{ "inline", RID_INLINE, D_EXT89 },
{ "int", RID_INT, 0 },
+ { "lengthof", RID_LENGTHOF, D_EXT },
{ "long", RID_LONG, 0 },
{ "mutable", RID_MUTABLE, D_CXXONLY | D_CXXWARN },
{ "namespace", RID_NAMESPACE, D_CXXONLY | D_CXXWARN },
@@ -4070,6 +4072,24 @@ c_alignof_expr (location_t loc, tree expr)
return fold_convert_loc (loc, size_type_node, t);
}
+
+/* Implement the _Lengthof keyword: Return the length of an array,
+ that is, the number of elements in the array. */
+
+tree
+c_lengthof_type (location_t loc, tree type)
+{
+ enum tree_code type_code;
+
+ type_code = TREE_CODE (type);
+ if (type_code != ARRAY_TYPE)
+ {
+ error_at (loc, "invalid application of %<_Lengthof%> to type %qT", type);
+ return error_mark_node;
+ }
+
+ return array_type_nelts_top (type);
+}
/* Handle C and C++ default attributes. */
@@ -50,6 +50,10 @@ DEFTREECODE (EXCESS_PRECISION_EXPR, "excess_precision_expr", tcc_expression, 1)
number. */
DEFTREECODE (USERDEF_LITERAL, "userdef_literal", tcc_exceptional, 3)
+/* Represents a 'sizeof' expression during C++ template expansion,
+ or for the purpose of -Wsizeof-pointer-memaccess warning. */
+DEFTREECODE (LENGTHOF_EXPR, "lengthof_expr", tcc_expression, 1)
+
/* Represents a 'sizeof' expression during C++ template expansion,
or for the purpose of -Wsizeof-pointer-memaccess warning. */
DEFTREECODE (SIZEOF_EXPR, "sizeof_expr", tcc_expression, 1)
@@ -105,6 +105,7 @@ enum rid
/* C extensions */
RID_ASM, RID_TYPEOF, RID_TYPEOF_UNQUAL, RID_ALIGNOF, RID_ATTRIBUTE,
+ RID_LENGTHOF,
RID_VA_ARG,
RID_EXTENSION, RID_IMAGPART, RID_REALPART, RID_LABEL, RID_CHOOSE_EXPR,
RID_TYPES_COMPATIBLE_P, RID_BUILTIN_COMPLEX, RID_BUILTIN_SHUFFLE,
@@ -885,6 +886,7 @@ extern tree c_common_truthvalue_conversion (location_t, tree);
extern void c_apply_type_quals_to_decl (int, tree);
extern tree c_sizeof_or_alignof_type (location_t, tree, bool, bool, int);
extern tree c_alignof_expr (location_t, tree);
+extern tree c_lengthof_type (location_t, tree);
/* Print an error message for invalid operands to arith operation CODE.
NOP_EXPR is used as a special case (see truthvalue_conversion). */
extern void binary_op_error (rich_location *, enum tree_code, tree, tree);
@@ -74,7 +74,17 @@ along with GCC; see the file COPYING3. If not see
#include "bitmap.h"
#include "analyzer/analyzer-language.h"
#include "toplev.h"
+
+#define c_parser_sizeof_expression(parser) \
+( \
+ c_parser_sizeof_or_lengthof_expression (parser, RID_SIZEOF) \
+)
+#define c_parser_lengthof_expression(parser) \
+( \
+ c_parser_sizeof_or_lengthof_expression (parser, RID_LENGTHOF) \
+)
+
/* We need to walk over decls with incomplete struct/union/enum types
after parsing the whole translation unit.
In finish_decl(), if the decl is static, has incomplete
@@ -1687,7 +1697,7 @@ static struct c_expr c_parser_binary_expression (c_parser *, struct c_expr *,
tree);
static struct c_expr c_parser_cast_expression (c_parser *, struct c_expr *);
static struct c_expr c_parser_unary_expression (c_parser *);
-static struct c_expr c_parser_sizeof_expression (c_parser *);
+static struct c_expr c_parser_sizeof_or_lengthof_expression (c_parser *, enum rid);
static struct c_expr c_parser_alignof_expression (c_parser *);
static struct c_expr c_parser_postfix_expression (c_parser *);
static struct c_expr c_parser_postfix_expression_after_paren_type (c_parser *,
@@ -9864,6 +9874,8 @@ c_parser_unary_expression (c_parser *parser)
case CPP_KEYWORD:
switch (c_parser_peek_token (parser)->keyword)
{
+ case RID_LENGTHOF:
+ return c_parser_lengthof_expression (parser);
case RID_SIZEOF:
return c_parser_sizeof_expression (parser);
case RID_ALIGNOF:
@@ -9903,12 +9915,13 @@ c_parser_unary_expression (c_parser *parser)
/* Parse a sizeof expression. */
static struct c_expr
-c_parser_sizeof_expression (c_parser *parser)
+c_parser_sizeof_or_lengthof_expression (c_parser *parser, enum rid rid)
{
+ const char *op_name = (rid == RID_SIZEOF) ? "sizeof" : "_Lengthof";
struct c_expr expr;
struct c_expr result;
location_t expr_loc;
- gcc_assert (c_parser_next_token_is_keyword (parser, RID_SIZEOF));
+ gcc_assert (c_parser_next_token_is_keyword (parser, rid));
location_t start;
location_t finish = UNKNOWN_LOCATION;
@@ -9952,13 +9965,16 @@ c_parser_sizeof_expression (c_parser *parser)
}
/* sizeof ( type-name ). */
if (scspecs)
- error_at (expr_loc, "storage class specifier in %<sizeof%>");
+ error_at (expr_loc, "storage class specifier in %qs", op_name);
if (type_name->specs->alignas_p)
error_at (type_name->specs->locations[cdw_alignas],
- "alignment specified for type name in %<sizeof%>");
+ "alignment specified for type name in %qs", op_name);
c_inhibit_evaluation_warnings--;
in_sizeof--;
- result = c_expr_sizeof_type (expr_loc, type_name);
+ if (rid == RID_LENGTHOF)
+ result = c_expr_lengthof_type (expr_loc, type_name);
+ else
+ result = c_expr_sizeof_type (expr_loc, type_name);
}
else
{
@@ -9971,8 +9987,11 @@ c_parser_sizeof_expression (c_parser *parser)
mark_exp_read (expr.value);
if (TREE_CODE (expr.value) == COMPONENT_REF
&& DECL_C_BIT_FIELD (TREE_OPERAND (expr.value, 1)))
- error_at (expr_loc, "%<sizeof%> applied to a bit-field");
- result = c_expr_sizeof_expr (expr_loc, expr);
+ error_at (expr_loc, "%qs applied to a bit-field", op_name);
+ if (rid == RID_LENGTHOF)
+ result = c_expr_lengthof_expr (expr_loc, expr);
+ else
+ result = c_expr_sizeof_expr (expr_loc, expr);
}
if (finish == UNKNOWN_LOCATION)
finish = start;
@@ -736,6 +736,7 @@ extern int c_type_dwarf_attribute (const_tree, int);
/* in c-typeck.cc */
extern int in_alignof;
extern int in_sizeof;
+extern int in_lengthof;
extern int in_typeof;
extern bool c_in_omp_for;
extern bool c_omp_array_section_p;
@@ -786,6 +787,9 @@ extern tree build_external_ref (location_t, tree, bool, tree *);
extern void pop_maybe_used (bool);
extern struct c_expr c_expr_sizeof_expr (location_t, struct c_expr);
extern struct c_expr c_expr_sizeof_type (location_t, struct c_type_name *);
+extern struct c_expr c_expr_lengthof_expr (location_t, struct c_expr);
+extern struct c_expr c_expr_lengthof_type (location_t loc,
+ struct c_type_name *);
extern struct c_expr parser_build_unary_op (location_t, enum tree_code,
struct c_expr);
extern struct c_expr parser_build_binary_op (location_t,
@@ -3453,6 +3453,90 @@ c_expr_sizeof_type (location_t loc, struct c_type_name *t)
return ret;
}
+/* Return the result of _Lengthof applied to EXPR. */
+
+struct c_expr
+c_expr_lengthof_expr (location_t loc, struct c_expr expr)
+{
+ struct c_expr ret;
+ if (expr.value == error_mark_node)
+ {
+ ret.value = error_mark_node;
+ ret.original_code = ERROR_MARK;
+ ret.original_type = NULL;
+ ret.m_decimal = 0;
+ pop_maybe_used (false);
+ }
+ else
+ {
+ bool expr_const_operands = true;
+
+ tree folded_expr = c_fully_fold (expr.value, require_constant_value,
+ &expr_const_operands);
+ ret.value = c_lengthof_type (loc, TREE_TYPE (folded_expr));
+ c_last_sizeof_arg = expr.value;
+ c_last_sizeof_loc = loc;
+ ret.original_code = LENGTHOF_EXPR;
+ ret.original_type = NULL;
+ ret.m_decimal = 0;
+ if (C_TYPE_VARIABLE_SIZE (TREE_TYPE (folded_expr)))
+ {
+ /* _Lengthof is evaluated when given a vla. */
+ ret.value = build2 (C_MAYBE_CONST_EXPR, TREE_TYPE (ret.value),
+ folded_expr, ret.value);
+ C_MAYBE_CONST_EXPR_NON_CONST (ret.value) = !expr_const_operands;
+ SET_EXPR_LOCATION (ret.value, loc);
+ }
+ pop_maybe_used (C_TYPE_VARIABLE_SIZE (TREE_TYPE (folded_expr)));
+ }
+ return ret;
+}
+
+/* Return the result of _Lengthof applied to T, a structure for the type
+ name passed to _lengthof (rather than the type itself). LOC is the
+ location of the original expression. */
+
+struct c_expr
+c_expr_lengthof_type (location_t loc, struct c_type_name *t)
+{
+ tree type;
+ struct c_expr ret;
+ tree type_expr = NULL_TREE;
+ bool type_expr_const = true;
+ type = groktypename (t, &type_expr, &type_expr_const);
+ ret.value = c_lengthof_type (loc, type);
+ c_last_sizeof_arg = type;
+ c_last_sizeof_loc = loc;
+ ret.original_code = LENGTHOF_EXPR;
+ ret.original_type = NULL;
+ ret.m_decimal = 0;
+ if (type == error_mark_node)
+ {
+ ret.value = error_mark_node;
+ ret.original_code = ERROR_MARK;
+ }
+ else
+ if ((type_expr || TREE_CODE (ret.value) == INTEGER_CST)
+ && C_TYPE_VARIABLE_SIZE (type))
+ {
+ /* If the type is a [*] array, it is a VLA but is represented as
+ having a size of zero. In such a case we must ensure that
+ the result of _Lengthof does not get folded to a constant by
+ c_fully_fold, because if the length is evaluated the result is
+ not constant and so constraints on zero or negative size
+ arrays must not be applied when this _Lengthof call is inside
+ another array declarator. */
+ if (!type_expr)
+ type_expr = integer_zero_node;
+ ret.value = build2 (C_MAYBE_CONST_EXPR, TREE_TYPE (ret.value),
+ type_expr, ret.value);
+ C_MAYBE_CONST_EXPR_NON_CONST (ret.value) = !type_expr_const;
+ }
+ pop_maybe_used (type != error_mark_node
+ ? C_TYPE_VARIABLE_SIZE (type) : false);
+ return ret;
+}
+
/* Build a function call to function FUNCTION with parameters PARAMS.
The function call is at LOC.
PARAMS is a list--a chain of TREE_LIST nodes--in which the
@@ -91,6 +91,7 @@ DEF_OPERATOR ("co_await", CO_AWAIT_EXPR, "aw", OVL_OP_FLAG_UNARY)
/* These are extensions. */
DEF_OPERATOR ("alignof", ALIGNOF_EXPR, "az", OVL_OP_FLAG_UNARY)
+DEF_OPERATOR ("lengthof", LENGTHOF_EXPR, "lz", OVL_OP_FLAG_UNARY)
DEF_OPERATOR ("__imag__", IMAGPART_EXPR, "v18__imag__", OVL_OP_FLAG_UNARY)
DEF_OPERATOR ("__real__", REALPART_EXPR, "v18__real__", OVL_OP_FLAG_UNARY)
new file mode 100644
@@ -0,0 +1,35 @@
+/* Copyright (C) 2024 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3, or (at your option)
+any later version.
+
+GCC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+Under Section 7 of GPL version 3, you are granted additional
+permissions described in the GCC Runtime Library Exception, version
+3.1, as published by the Free Software Foundation.
+
+You should have received a copy of the GNU General Public License and
+a copy of the GCC Runtime Library Exception along with this program;
+see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
+<http://www.gnu.org/licenses/>. */
+
+#ifndef _STDLENGTH_H
+#define _STDLENGTH_H
+
+#if (!defined __cplusplus)
+
+#define lengthof _Lengthof
+
+#define __lengthof_is_defined 1
+
+#endif
+
+#endif /* stdlength.h */
@@ -245,6 +245,9 @@ enum type_context_kind {
/* Directly measuring the alignment of T. */
TCTX_ALIGNOF,
+ /* Directly measuring the length of array T. */
+ TCTX_LENGTHOF,
+
/* Creating objects of type T with static storage duration. */
TCTX_STATIC_STORAGE,
This operator is similar to sizeof() but can only be applied to an array, and returns its length (number of elements). FUTURE DIRECTIONS: We could make it work with array parameters to functions, and somehow magically return the length designator of the array, regardless of it being really a pointer. Link: <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n2529.pdf> Cc: Gabriel Ravier <gabravier@gmail.com> Cc: Martin Uecker <uecker@tugraz.at> Cc: Joseph Myers <josmyers@redhat.com> Signed-off-by: Alejandro Colomar <alx@kernel.org> --- gcc/Makefile.in | 1 + gcc/c-family/c-common.cc | 20 ++++++++++ gcc/c-family/c-common.def | 4 ++ gcc/c-family/c-common.h | 2 + gcc/c/c-parser.cc | 35 ++++++++++++---- gcc/c/c-tree.h | 4 ++ gcc/c/c-typeck.cc | 84 +++++++++++++++++++++++++++++++++++++++ gcc/cp/operators.def | 1 + gcc/ginclude/stdlength.h | 35 ++++++++++++++++ gcc/target.h | 3 ++ 10 files changed, 181 insertions(+), 8 deletions(-) create mode 100644 gcc/ginclude/stdlength.h